震波
在一片土地上有 $N$ 个城市,通过 $N-1$ 条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为 $1$,其中第 $i$ 个城市的价值为 $value[i]$。
不幸的是,这片土地常常发生地震,并且随着时代的发展,城市的价值也往往会发生变动。
不幸的是,这片土地常常发生地震,并且随着时代的发展,城市的价值也往往会发生变动。
接下来你需要在线处理 $M$ 次操作:
- $0~x~k$ 表示发生了一次地震,震中城市为 $x$ ,影响范围为 $k$ ,所有与 $x$ 距离不超过 $k$ 的城市都将受到影响,该次地震造成的经济损失为所有受影响城市的价值和。
- $1~x~y$ 表示第$x$个城市的价值变成了 $y$ 。
- $0~x~k$ 表示发生了一次地震,震中城市为 $x$ ,影响范围为 $k$ ,所有与 $x$ 距离不超过 $k$ 的城市都将受到影响,该次地震造成的经济损失为所有受影响城市的价值和。
- $1~x~y$ 表示第$x$个城市的价值变成了 $y$ 。
为了体现程序的在线性,操作中的 $x$ 、$y$ 、$k$ 都需要异或你程序上一次的输出来解密,如果之前没有输出,则默认上一次的输出为 $0$ 。
Solution
考虑建出点分树,每一个点开一棵以长度为下标的线段树。
查询时可以一步步往上跳。假设他到父亲的权值为t,每此查询与x距离为k k+t ...的点。
可是这样会算重。
那么可以在每个点再开一棵线段树,下标为点到他点分树上父亲的权值。
每次减去第二棵线段树中k+t的值。也就是自己与父亲相同的贡献
考虑建出点分树,每一个点开一棵以长度为下标的线段树。
查询时可以一步步往上跳。假设他到父亲的权值为t,每此查询与x距离为k k+t ...的点。
可是这样会算重。
那么可以在每个点再开一棵线段树,下标为点到他点分树上父亲的权值。
每次减去第二棵线段树中k+t的值。也就是自己与父亲相同的贡献
卡常毒题
orz邵神树状数组常树优秀
orz邵神树状数组常树优秀
1 #include<cstdio> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstring> 5 #include<algorithm> 6 #include<cmath> 7 #define maxn 200006 8 using namespace std; 9 int n,m,head[maxn],a[maxn],val[maxn],siz,tot,deep[maxn]; 10 int f[maxn],vis[maxn],par[maxn],sz[maxn],rt; 11 int cnt,root[maxn],st[maxn][20],sc,dfn[maxn],l2[maxn]; 12 struct node{ 13 int v,nex; 14 }e[maxn]; 15 struct no{ 16 int ls,rs,v; 17 }tr[maxn*140]; 18 inline void lca(int k,int fa){ 19 st[dfn[k]=++sc][0]=deep[k]=deep[fa]+1; 20 for(int i=head[k];i;i=e[i].nex)if(e[i].v!=fa)lca(e[i].v,k),st[++sc][0]=deep[k]; 21 } 22 inline void add(int &k,int l,int r,int pl,int v){ 23 if(!k)k=++cnt; 24 if(l==r){tr[k].v+=v;return;} 25 int mid=l+r>>1; 26 if(pl<=mid)add(tr[k].ls,l,mid,pl,v); 27 else add(tr[k].rs,mid+1,r,pl,v); 28 tr[k].v=tr[tr[k].ls].v+tr[tr[k].rs].v; 29 } 30 inline int ask(int k,int l,int r,int pl){ 31 if(!k||pl<0)return 0; 32 if(l==r)return tr[k].v; 33 int mid=l+r>>1; 34 if(pl<=mid)return ask(tr[k].ls,l,mid,pl); 35 else return tr[tr[k].ls].v+ask(tr[k].rs,mid+1,r,pl); 36 37 } 38 inline int dis(int x,int y){ 39 if(dfn[y]<dfn[x])swap(x,y); 40 int i=l2[dfn[y]-dfn[x]+1]; 41 int dl=min(st[dfn[x]][i],st[dfn[y]-(1<<i)+1][i]); 42 return deep[x]+deep[y]-(dl<<1); 43 } 44 inline void dfs(int o,int la,int k,int fa){ 45 add(root[o],0,n,dis(o,k),val[k]); 46 if(la)add(root[o+n],0,n,dis(k,la),val[k]); 47 sz[k]=1; 48 for(int i=head[k];i;i=e[i].nex){ 49 if(e[i].v==fa||vis[e[i].v])continue; 50 dfs(o,la,e[i].v,k); 51 sz[k]+=sz[e[i].v]; 52 } 53 } 54 inline void findr(int k,int fa){ 55 sz[k]=1;f[k]=0; 56 for(int i=head[k];i;i=e[i].nex){ 57 if(e[i].v==fa||vis[e[i].v])continue; 58 findr(e[i].v,k); 59 sz[k]+=sz[e[i].v]; 60 f[k]=max(f[k],sz[e[i].v]); 61 } 62 f[k]=max(f[k],siz-sz[k]); 63 if(f[k]<f[rt])rt=k; 64 } 65 inline void work(int k,int la){ 66 vis[k]=1; 67 dfs(k,la,k,0); 68 for(int i=head[k];i;i=e[i].nex){ 69 if(!vis[e[i].v]){ 70 siz=sz[e[i].v];rt=0;findr(e[i].v,k); 71 par[rt]=k; 72 work(rt,k); 73 } 74 } 75 } 76 inline int R(){ 77 int v=0;char ch; 78 while(!isdigit(ch=getchar()));v=ch-48; 79 while(isdigit(ch=getchar()))v=(v<<1)+(v<<3)+ch-48; 80 return v; 81 } 82 int main() 83 { 84 n=R();m=R(); 85 for(int i=1;i<=n;i++)val[i]=R(); 86 for(int i=1,t1,t2;i<n;i++){ 87 t1=R();t2=R(); 88 e[++tot].v=t2;e[tot].nex=head[t1];head[t1]=tot; 89 e[++tot].v=t1;e[tot].nex=head[t2];head[t2]=tot; 90 } 91 lca(1,0); 92 for(int i=2;i<=sc;i++)l2[i]=l2[i/2]+1; 93 for(int j=1;j<=l2[sc];j++) 94 for(int i=1;i+(1<<j)<=sc+1;i++)st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]); 95 rt=0;f[0]=1e9;siz=n;findr(1,0); 96 work(rt,0); 97 int ans=0; 98 for(int i=1,op,y,x,k;i<=m;i++){ 99 op=R(); 100 if(op==0){ 101 x=R();k=R(); 102 x^=ans,k^=ans; 103 ans=0;int fi=x; 104 for(int d=0;x;){ 105 ans+=ask(root[x],0,n,k-d);d=dis(par[x],fi); 106 if(par[x])ans-=ask(root[n+x],0,n,k-d); 107 x=par[x]; 108 } 109 printf("%d\n",ans); 110 } 111 if(op==1){ 112 x=R();y=R(); 113 x^=ans;y^=ans; 114 int fi=x; 115 for(int d=0;x;){ 116 add(root[x],0,n,d,y-val[fi]);d=dis(fi,par[x]); 117 if(par[x])add(root[n+x],0,n,d,y-val[fi]); 118 x=par[x]; 119 } 120 val[fi]=y; 121 } 122 } 123 return 0; 124 }