日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

P3258 [JLOI2014]松鼠的新家

發布時間:2023/12/3 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 P3258 [JLOI2014]松鼠的新家 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • 題意:
    • 題解:
      • 樹上差分
      • 代碼:
      • 樹鏈剖分
      • 代碼:

P3258 [JLOI2014]松鼠的新家

題意:

n個點,n-1條邊,給出每個點的拜訪順序,問每個點經過幾次(最后一次移動不算拜訪)

題解:

題意明確后就很好做了,對于給定的x和y,我們只需要分別將x和y到lca(x,y)經過的點加一即可
但是這樣直接做肯定不行
有兩個方法:

  • 樹上差分
  • 樹鏈剖分
  • 樹上差分

    參考題解
    我們先考慮對于數組,我們指定連續一段加一
    我們現在對a2到a6區間進行加一
    現在處理差分數組,我們對a2加一,對a7減一
    差分屬豬的定義:a[i] = a[i-1] + 差分數組[i]
    也就是我們并沒有改變區間的值,而是改變的兩個數之間的相對大小

    對于樹上差分:
    父親節點u = 其所有的子節點 + 他本身的差分數組
    我們現在改變S到T邊上所有點的值
    我們對S的父親節點減1,對T加1

    //把s->t路徑上所有點均加w, chafen[t] += w; chafen[s的父節點] -= w;

    當計算每個點具體值時:

    for(遍歷與 u 相連的每一個子節點 v){num[u] += num[v]; } num[u] += chafen[u];//加上差分數組


    在本題中結合lca即可

    代碼:

    #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> using namespace std;const int maxn = 300050; const int maxm = maxn << 1; int N, M; int a[maxn], t1, t2; int head[maxn], cnt;struct Edge{int u, v, next; }edge[maxm];inline void addedge(int u, int v){edge[++cnt].u = u;edge[cnt].v = v;edge[cnt].next = head[u];head[u] = cnt; }int fa[maxn][31], dep[maxn];void dfs(int u, int faa){fa[u][0] = faa, dep[u] = dep[faa] + 1;for(int i = 1; i <= 30; i++){fa[u][i] = fa[ fa[u][i - 1] ][i - 1];}for(int i = head[u]; i ; i = edge[i].next){int v = edge[i].v;if(v == faa)continue;dfs(v, u);} } inline int lca(int x, int y){if(dep[x] < dep[y])swap(x,y);for(int i = 30; i >= 0; i--){if(dep[ fa[x][i] ] >= dep[y]) x = fa[x][i];}if(x == y)return x;for(int i = 30; i >= 0; i--){if(fa[x][i] != fa[y][i]){x = fa[x][i], y = fa[y][i];}}return fa[x][0]; }int num[maxn];int answer(int u, int faa){for(int i = head[u]; i ; i = edge[i].next){int v = edge[i].v;if(v == faa)continue;answer(v, u);num[u] += num[v];} } int main(){cin>>N;for(int i = 1; i <= N; i++){cin>> a[i];}for(int i = 1; i < N; i++){cin>> t1>> t2;addedge(t1, t2);addedge(t2, t1);}dfs(1, 0);for(int i = 1; i <= N - 1; i++){int u = a[i], v = a[i + 1];int t = lca(u, v);num[ fa[t][0] ] -= 1;num[ t ] -= 1;num[ u ] += 1;num[ v ] += 1;}answer(1,0);for(int i = 2; i <= N; i++){num[a[i]]--;}for(int i = 1; i <= N; i++){cout<<num[i]<<endl;} }

    樹鏈剖分

    樹鏈剖分就直接進行區間修改加一就行哈

    代碼:

    這個代碼我調了半個晚上,哭了哭了,終于調好了

    #include<bits/stdc++.h> typedef long long ll; using namespace std; inline int read(){int s=0,w=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);return s*w; } const int maxn=1e6+9; int a[maxn]; struct node{int u,v,next; }edge[maxn]; int cnt=0; int tot=0; int n; int head[maxn]; void add(int u,int v) {edge[++cnt].v=v;edge[cnt].next=head[u];head[u]=cnt; } //--- int tr[maxn<<2],laz[maxn<<2]; inline void pushup(int rt) {tr[rt]=tr[rt<<1]+tr[rt<<1|1]; } inline void pushdown(int rt,int l,int r) {int len=(r-l+1);laz[rt<<1]+=laz[rt];laz[rt<<1|1]+=laz[rt];tr[rt<<1]+=laz[rt]*(len-(len>>1));tr[rt<<1|1]+=laz[rt]*(len>>1);laz[rt]=0; } inline void build(int rt,int l,int r) {if(l==r){tr[rt]=0;return ;}int mid=l+r>>1; build(rt<<1,l,mid);build(rt<<1|1,mid+1,r);pushup(rt); } inline int query(int rt,int l,int r,int ip) {if(l==ip&&r==ip)return tr[rt];if(laz[rt])pushdown(rt,l,r);int mid=l+r>>1;int ress=0;if(ip<=mid)ress+=query(rt<<1,l,mid,ip);if(ip>mid)ress+=query(rt<<1|1,mid+1,r,ip);return ress; } inline void update(int rt,int l,int r,int L,int R,int k) {if(L<=l&&r<=R){int len=(r-l+1);laz[rt]+=k;tr[rt]+=k*len;}else {if(laz[rt])pushdown(rt,l,r);int mid=l+r>>1;if(L<=mid)update(rt<<1,l,mid,L,R,k);if(R>mid)update(rt<<1|1,mid+1,r,L,R,k);pushup(rt);} } //--- int fa[maxn],dep[maxn],siz[maxn],id[maxn],top[maxn],son[maxn]; inline int updrange(int x,int y,int k) {while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]])swap(x,y);update(1,1,n,id[top[x]],id[x],k);x=fa[top[x]];}if(dep[x]>dep[y])swap(x,y);update(1,1,n,id[x],id[y],k); } inline void dfs1(int x,int f,int deep) {dep[x]=deep;fa[x]=f;siz[x]=1;int maxson=-1;for(int i=head[x];i;i=edge[i].next){int v=edge[i].v;if(v==f)continue;dfs1(v,x,deep+1);siz[x]+=siz[v];if(siz[v]>maxson){son[x]=v;maxson=siz[v];}} } inline void dfs2(int x,int topf) {id[x]=++tot;top[x]=topf;if(!son[x])return ;dfs2(son[x],topf);for(int i=head[x];i;i=edge[i].next){int v=edge[i].v;if(v==fa[x]||v==son[x])continue;dfs2(v,v);} } void print() {for(int i=1;i<=n;i++){printf("%d\n",query(1,1,n,id[i]));//cout<<<<endl;} // printf("----\n"); } int main() {cin>>n;for(int i=1;i<=n;i++)cin>>a[i];for(int i=1;i<n;i++){int x,y;cin>>x>>y;add(x,y);add(y,x);}dfs1(a[n],0,1);dfs2(a[n],a[n]);build(1,1,n);updrange(a[1],a[1],1);//print();for(int i=1;i<n;i++){updrange(a[i],a[i+1],1);updrange(a[i],a[i],-1);// print();}updrange(a[n],a[n],-1);print();return 0; }

    總結

    以上是生活随笔為你收集整理的P3258 [JLOI2014]松鼠的新家的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。