bzoj3730. 震波
生活随笔
收集整理的這篇文章主要介紹了
bzoj3730. 震波
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
動態點分治
考慮從每一個"塊"里找到距離k范圍內的點的和
為了去重,
每個x維護兩個線段樹:(都是關于自己分治樹子樹的點)
1.下標為距離x的距離,權值為val的
2.下標為距離x的分治樹father的距離,權值為val
?
這樣,統計的時候
計算分治樹祖先塊的時候,把從自己那里出來的塊的東西再減去
?
注意:
1.點分治nowrt是全局變量,所以divi這一層用tmp額外記錄一下,否則回溯回來再下去的時候,nowrt就不是這一層的了
2.不能某個祖先的dis大于k,就直接break了。因為到分治樹祖先的距離沒有單調性!!!!
?
代碼:
#include<bits/stdc++.h> #define il inline #define reg register int #define numb (ch^'0') #define mid ((l+r)>>1) using namespace std; typedef long long ll; il void rd(int &x){char ch;bool fl=false;while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);for(x=numb;isdigit(ch=getchar());x=x*10+numb);(fl==true)&&(x=-x); } namespace Miracle{ const int N=100000+5; int n,m; struct node{int nxt,to; }e[2*N]; int hd[N],cnt; void add(int x,int y){e[++cnt].nxt=hd[x];e[cnt].to=y;hd[x]=cnt; } int fa[N]; int sz[N]; int mx[N]; int nowsz; int tmprt; int rt[N][2];//0 is myself ; 1 is disfather int nowrt; struct tr{int ls,rs;int sum; }t[N*50]; int tot; int dist[N][20]; int dep[N]; int val[N]; int vis[N]; void pushup(int x){t[x].sum=t[t[x].ls].sum+t[t[x].rs].sum; } void upda(int &x,int l,int r,int p,int v){if(!x) x=++tot;if(l==r){t[x].sum+=v;return;}if(p<=mid) upda(t[x].ls,l,mid,p,v);else upda(t[x].rs,mid+1,r,p,v);pushup(x); } int query(int x,int l,int r,int L,int R){//no dis=0 (myself)if(L>R) return 0;if(L<=l&&r<=R){return t[x].sum;}int ret=0;if(L<=mid) ret+=query(t[x].ls,l,mid,L,R);if(mid<R) ret+=query(t[x].rs,mid+1,r,L,R);return ret; } void dfs1(int x,int f,int d,int dis){//find nowrtsz[x]=1;mx[x]=0;dep[x]=d;if(d!=1){upda(tmprt,0,n,dis,val[x]);}for(reg i=hd[x];i;i=e[i].nxt){int y=e[i].to;if(vis[y]||y==f) continue;dfs1(y,x,d,dis+1);sz[x]+=sz[y];mx[x]=max(mx[x],sz[y]);}mx[x]=max(mx[x],nowsz-sz[x]);if(mx[x]<=nowsz/2&&(nowsz-sz[x])<=nowsz/2){nowrt=x;} } void dfs2(int x,int f,int d,int dis){//find dis from nowrtsz[x]=1;dep[x]=d;dist[x][d]=dis;upda(rt[nowrt][0],0,n,dis,val[x]);for(reg i=hd[x];i;i=e[i].nxt){int y=e[i].to;if(vis[y]||y==f) continue;dfs2(y,x,d,dis+1);sz[x]+=sz[y];} } void divi(int x,int d,int f){//mxsz=0; // cout<<" x "<<x<<" : "<<d<<" "<<f<<endl;nowrt=0;tmprt=0;dfs1(x,0,d,1);fa[nowrt]=f;rt[nowrt][1]=tmprt; // cout<<" nowrt "<<nowrt<<endl;dfs2(nowrt,0,d,0);vis[nowrt]=1;int tmp=nowrt;for(reg i=hd[tmp];i;i=e[i].nxt){int y=e[i].to;if(!vis[y]){nowsz=sz[y];divi(y,d+1,tmp);}} } int wrk0(int x,int k){int ret=0;ret+=query(rt[x][0],0,n,0,k);int tmp=x;while(fa[x]){int y=fa[x];// if(k-dist[tmp][dep[y]]>=0) ret+=query(rt[y][0],0,n,0,k-dist[tmp][dep[y]]);// else break;ret-=query(rt[x][1],0,n,0,k-dist[tmp][dep[y]]);x=y;}return ret; } void wrk1(int x,int v){int tmp=x;int c=v-val[x];val[x]=v;upda(rt[x][0],0,n,0,c);while(fa[x]){int y=fa[x];upda(rt[x][1],0,n,dist[tmp][dep[y]],c);upda(rt[y][0],0,n,dist[tmp][dep[y]],c);x=y;} } int main(){rd(n);rd(m);for(reg i=1;i<=n;++i) rd(val[i]);int x,y;for(reg i=1;i<n;++i){rd(x);rd(y);add(x,y);add(y,x);}nowsz=n;divi(1,1,0); // cout<<" toot "<<tot<<endl;int op,k;int lasans=0;while(m--){rd(op);rd(x);rd(k);x^=lasans;k^=lasans;if(op==0) printf("%d\n",lasans=wrk0(x,k));else wrk1(x,k);}return 0; }} signed main(){ // freopen("data.in","r",stdin); // freopen("my.out","w",stdout); Miracle::main();return 0; }/*Author: *Miracle*Date: 2019/2/6 10:11:29 */總結:
動態點分治往往為了去重,經常考慮x對fa的貢獻
相當于在分治樹的往fa走的邊上造了一個線段樹
(每個點一個,每個邊一個,一共n+n-1個)
轉載于:https://www.cnblogs.com/Miracevin/p/10353703.html
總結
以上是生活随笔為你收集整理的bzoj3730. 震波的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 海康、大华等网络摄像头RTSP_Onvi
- 下一篇: 分享一个自己写的取中国农历相关数据的类。