BZOJ3730 震波 【动态点分治】
生活随笔
收集整理的這篇文章主要介紹了
BZOJ3730 震波 【动态点分治】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
傳送門
SOL
點分樹模板
細節看注釋吧
多寫幾遍應該就好了
CODE
#include<bits/stdc++.h> using namespace std; #define sf scanf #define pf printf const int RLEN=1<<18|1; inline char gc(){static char ibuf[RLEN],*ib,*ob;(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));return (ib==ob)?EOF:*ib++; } inline int read(){char ch=gc();int res=0,f=1;while(!isdigit(ch))ch=gc();while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();return res; } const int N=1e5+10; #define lb(x) (x&(-x)) struct vec{vector <int> v;int n;inline void init(){v.assign(n+10,0);}inline void update(int p,int k){//p的距離可以是0,所以要向左唯一一位 ++p;for(;p<=n;p+=lb(p))v[p]+=k;}inline int query(int p,int res=0){//兩點間距離最長是 n-1 所以 (n-1)+1 剛好到 n的邊界//如果負數for循環都沒有//如果大于n給n就可以了 p=min(p+1,n);for(;p>=1;p-=lb(p))res+=v[p];return res;}inline void write(){for(int i=1;i<=n;++i)cout<<query(i-1)<<' ';puts("");} }f1[N],f2[N]; int n,m,vis[N],val[N],adj[N],nxt[N<<1],to[N<<1],cnt,dep[N],siz[N],son[N],fa[N],maxn,rt; int ecnt,d[N];namespace ST{//st表加歐拉序 o(1)求兩點間距離 int dis[N],dfn,pos[N],st[22][N<<2],lg[N<<2];void dfs(int u,int f){st[0][++dfn]=dis[u],pos[u]=dfn;for(int e=adj[u];e;e=nxt[e]){int v=to[e];if(v==f)continue;dis[v]=dis[u]+1;dfs(v,u);st[0][++dfn]=dis[u];}}inline void init(){dfs(1,0);lg[0]=-1;for(int i=1;i<=dfn;++i)lg[i]=lg[i>>1]+1;for(int i=1;(1<<i)<=dfn;++i){for(int j=1;j+(1<<i)-1<=dfn;++j){st[i][j]=min(st[i-1][j],st[i-1][j+(1<<i-1)]);} }}inline int dist(int u,int v){int x=pos[u],y=pos[v];if(x>y)swap(x,y);int t=lg[y-x+1];return dis[u]+dis[v]-2*min(st[t][x],st[t][y-(1<<t)+1]);} } using namespace ST; inline void addedge(int u,int v){nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v; } void getrt(int u,int f){siz[u]=1,son[u]=0;for(int e=adj[u];e;e=nxt[e]){int v=to[e];if(v^f&&!vis[v]){getrt(v,u),siz[u]+=siz[v];son[u]=max(son[u],siz[v]);}}son[u]=max(son[u],maxn-siz[u]);if(son[u]<son[rt])rt=u; } void getdis(int u,int f){d[dep[u]]+=val[u],ecnt=max(ecnt,dep[u]);for(int e=adj[u];e;e=nxt[e]){int v=to[e];if(!vis[v]&&v^f){dep[v]=dep[u]+1;getdis(v,u);}} } inline void calc(vec &tr){tr.n=ecnt+1,tr.init();for(int i=0;i<=ecnt;++i){tr.update(i,d[i]),d[i]=0;}ecnt=0; } void solve(int u){//先把點分樹預處理出來 vis[u]=1;dep[u]=0;getdis(u,0);calc(f1[u]);for(int e=adj[u];e;e=nxt[e]){int v=to[e];if(vis[v])continue;son[0]=maxn=siz[v];getrt(v,rt=0),fa[rt]=u,dep[v]=1,getdis(v,0);//這里getdis是從v出發(取決于計算貢獻的方式)//但是值是放在分治中心 (rt)的樹狀數組里面 calc(f2[rt]),dep[v]=0;solve(rt);} } //從下往上,把相關聯的分治中心更新或者詢問即可 inline void update(int u,int k){for(int i=u;i;i=fa[i]){f1[i].update(dist(i,u),k);}// 這里是把 修改的點和 當前中心點的路徑的下標作修改 for(int i=u;fa[i];i=fa[i]){f2[i].update(dist(u,fa[i]),k);} } inline int query(int u,int k){int res=0;for(int i=u;i;i=fa[i]){res+=f1[i].query(k-dist(i,u));}for(int i=u;fa[i];i=fa[i]){res-=f2[i].query(k-dist(fa[i],u));}return res; } int last; signed main(){n=read();m=read();for(int i=1;i<=n;++i)val[i]=read();for(int i=1;i<n;++i){int u=read(),v=read();addedge(u,v),addedge(v,u);}init();maxn=son[0]=n;getrt(1,rt=0),solve(rt);while(m--){int op=read(),u=read()^last,k=read()^last;if(!op){cout<<(last=query(u,k))<<'\n';}else update(u,k-val[u]),val[u]=k;}return 0; }總結
以上是生活随笔為你收集整理的BZOJ3730 震波 【动态点分治】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 端午公司发了三颗荔枝
- 下一篇: [work] matplotlib的颜色