树分块&&树上莫队&&树上带修莫队
(王室联邦 树分块的裸体 xjb跑dfs就行了
树上莫队个人感觉就是dfs序+普通莫队就可以了
经典例题http://www.spoj.com/problems/COT2/
#include <bits/stdc++.h> #define ll long long #define N 40005 #define MAXN 100005 using namespace std; ll readll(){ ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int readint(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return f*x; } int n,q,size,p[N<<1],cnt1,cnt2,b[N<<1],cnt3,cnt; int begin[N],last[N]; ll a[N]; vector<ll>vec; vector<int>edge[N]; int num[N],son[N],dep[N],pre[N]; void dfs(int v,int fa,int deep){ b[++cnt3]=v;num[v]=1,dep[v]=deep+1;pre[v]=fa;begin[v]=cnt3; for(int i=0;i<edge[v].size();i++){ int u=edge[v][i]; if(u!=fa){ dfs(u,v,deep+1); num[v]+=num[u]; if(son[v]==-1||num[u]>num[son[v]]) son[v]=u; } } b[++cnt3]=v;last[v]=cnt3; } int tp[N]; void dfs2(int v,int td){ tp[v]=td; if(son[v]!=-1) dfs2(son[v],td); for(int i=0;i<edge[v].size();i++){ int u=edge[v][i]; if(u!=pre[v]&&u!=son[v]) dfs2(u,u); } } typedef struct node{ int l,r,biao,lca,flag; friend bool operator <(node aa,node bb){ if(p[aa.l]==p[bb.l]) return aa.r<bb.r; return p[aa.l]<p[bb.l]; } }node; int Lca(int u,int v){ int uu=tp[u];int vv=tp[v]; while(uu!=vv){ if(dep[uu]<dep[vv]){ swap(uu,vv);swap(u,v); } u=pre[uu];uu=tp[u]; } if(dep[u]>dep[v]) swap(u,v); return u; } node d[MAXN];int cont[N],vis[N]; int ans[MAXN],sum; void check(int R){ vis[b[R]]^=1; if(vis[b[R]]){ cont[a[b[R]]]++; if(cont[a[b[R]]]==1) sum++; } else{ cont[a[b[R]]]--; if(cont[a[b[R]]]==0) sum--; } } int main(){ ios::sync_with_stdio(false);cnt1=0;cnt2=0;cnt3=0;cnt=0; n=readint();q=readint();size=(int)sqrt(2*n); for(int i=1;i<=n;i++) son[i]=-1; for(int i=1;i<=n;i++) a[i]=readll(),vec.push_back(a[i]); for(int i=1;i<=2*n;i++) p[i]=(i-1)/size+1; sort(vec.begin(),vec.end()); int t=unique(vec.begin(),vec.end())-vec.begin(); for(int i=1;i<=n;i++) a[i]=lower_bound(vec.begin(),vec.begin()+t,a[i])-vec.begin()+1; int u,v; for(int i=1;i<n;i++){ u=readint();v=readint(); edge[u].push_back(v);edge[v].push_back(u); } dfs(1,-1,0);dfs2(1,1); int l,r; for(int i=1;i<=q;i++){ l=readint();r=readint();d[i].lca=Lca(l,r);d[i].biao=i; if(d[i].lca==l||d[i].lca==r) d[i].l=min(begin[l],begin[r]),d[i].r=max(begin[l],begin[r]),d[i].flag=1; else{ if(begin[l]<begin[r]) d[i].l=last[l],d[i].r=begin[r]; else d[i].l=last[r],d[i].r=begin[l]; } } sort(d+1,d+q+1); int L=1,R=0;sum=0; for(int i=1;i<=q;i++){ while(R>d[i].r){ check(R);R--; } while(R<d[i].r){ R++;check(R); } while(L>d[i].l){ L--;check(L); } while(L<d[i].l){ check(L);L++; } if(d[i].flag) ans[d[i].biao]=sum; else{ ans[d[i].biao]=sum; if(!cont[a[d[i].lca]]) ans[d[i].biao]++; } } for(int i=1;i<=q;i++) printf("%d\n",ans[i]); return 0; }
(对于树上带修莫队 会了树上莫队 加上一个带修操作 和普通带修莫队没啥区别 复杂度其他证明也基本类似
经典例题http://www.lydsy.com/JudgeOnline/problem.php?id=3052
#include <bits/stdc++.h> #define ll long long #define N 100005 #define MAXN 1000005 #define pii pair<int,int> using namespace std; ll readll(){ ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int readint(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return f*x; } int n,m,q; int a[N],p[N<<1],c[N]; ll V[N],W[N]; int b[N<<1],begin[N],last[N],cnt,fa[N],dep[N],size; int num[N],son[N],first[N],cnt1; pii Next[N<<1]; void add(int u,int v){ Next[++cnt1].first=first[u];Next[cnt1].second=v;first[u]=cnt1; Next[++cnt1].first=first[v];Next[cnt1].second=u;first[v]=cnt1; } void dfs(int u,int pre,int deep){ num[u]=1;dep[u]=deep+1;fa[u]=pre;b[++cnt]=u;begin[u]=cnt; for(int i=first[u];i!=-1;i=Next[i].first){ int v=Next[i].second; if(v!=pre){ dfs(v,u,deep+1); num[u]+=num[v]; if(son[u]==-1||num[v]>num[son[u]]) son[u]=v; } } b[++cnt]=u;last[u]=cnt; } int tp[N]; void dfs1(int v,int td){ tp[v]=td; if(son[v]!=-1) dfs1(son[v],td); for(int i=first[v];i!=-1;i=Next[i].first){ int u=Next[i].second; if(u!=fa[v]&&u!=son[v]) dfs1(u,u); } } int Lca(int u,int v){ int uu=tp[u];int vv=tp[v]; while(uu!=vv){ if(dep[uu]<dep[vv]){ swap(uu,vv);swap(u,v); } u=fa[uu];uu=tp[u]; } if(dep[u]>dep[v]) swap(u,v); return u; } typedef struct node{ int l,r,lca,biao;int t;bool flag; friend bool operator <(node aa,node bb){ if(p[aa.l]==p[bb.l]&&p[aa.r]==p[bb.r]) return aa.t<bb.t; else if(p[aa.l]==p[bb.l]) return p[aa.r]<p[bb.r]; else return p[aa.l]<p[bb.l]; } }node; node d[N];int vis[N],cont[1000006]; pii to[N],past[N]; ll ans[N],sum; void work(int pos){ vis[b[pos]]^=1; if(vis[b[pos]]){ cont[a[b[pos]]]++;sum+=1ll*W[cont[a[b[pos]]]]*V[a[b[pos]]]; } else{ cont[a[b[pos]]]--;sum-=1ll*W[cont[a[b[pos]]]+1]*V[a[b[pos]]]; } } void update(int l,int r,int t){ int u=to[t].first;int vul=to[t].second; // cout<<u<<"----"<<vul<<endl; int t1=begin[u];int t2=last[u]; int cp=0;int pos; if(t1>=l&&t1<=r) cp++,pos=t1; if(t2>=l&&t2<=r) cp++,pos=t2; // cout<<a[b[pos]]<<" "<<cp<<endl; if(cp==1){ cont[a[b[pos]]]--;;sum-=1ll*W[cont[a[b[pos]]]+1]*V[a[b[pos]]]; //cout<<sum<<endl; cont[vul]++;sum+=1ll*W[cont[vul]]*V[vul]; } a[u]=vul; } void restore(int l,int r,int t){ int u=past[t].first;int vul=past[t].second; int t1=begin[u];int t2=last[u]; int cp=0;int pos; if(t1>=l&&t1<=r) cp++,pos=t1; if(t2>=l&&t2<=r) cp++,pos=t2; if(cp==1){ cont[a[b[pos]]]--;;sum-=1ll*W[cont[a[b[pos]]]+1]*V[a[b[pos]]]; cont[vul]++;sum+=1ll*W[cont[vul]]*V[vul]; } a[u]=vul; } int main(){ ios::sync_with_stdio(false);cnt=cnt1=0; //cout<<size<<endl; n=readint();m=readint();q=readint(); size=(int)pow(2*n,2.0/3); for(int i=1;i<=2*n;i++) p[i]=(i-1)/size+1;; for(int i=1;i<=n;i++) son[i]=first[i]=-1; for(int i=1;i<=m;i++) V[i]=readll(); for(int i=1;i<=n;i++) W[i]=readll(); int u,v; for(int i=1;i<n;i++){ u=readint();v=readint(); add(u,v); } for(int i=1;i<=n;i++) c[i]=a[i]=readint(); dfs(1,-1,0);dfs1(1,1); //for(int i=1;i<=2*n;i++) cout<<b[i]<<" "; //cout<<endl; int op,l,r;int T=0;u=0; for(int i=1;i<=q;i++){ op=readint();l=readint();r=readint(); if(op==0){ to[++T].first=l;to[T].second=r; past[T].first=l;past[T].second=c[l]; c[l]=r; } else{ d[++u].lca=Lca(l,r);d[u].biao=u;d[u].t=T; if(d[u].lca==l||d[u].lca==r) d[u].l=min(begin[l],begin[r]),d[u].r=max(begin[l],begin[r]); else{ if(begin[l]>begin[r]) swap(l,r); d[u].l=last[l];d[u].r=begin[r];d[u].flag=1; } } } // cout<<u<<endl; sort(d+1,d+u+1);int L=1,R=0,t=0;sum=0; // for(int i=1;i<=u;i++){ // cout<<d[i].l<<" "<<d[i].r<<" "<<d[i].lca<<" "<<d[i].t<<endl; // } //for(int i=1;i<=2*n;i++) cout<<b[i]<<" "; // cout<<endl; for(int i=1;i<=u;i++){ // cout<<d[i].l<<"====="<<d[i].r<<" "<<d[i].t<<"======"<<d[i].biao<<endl; while(t>d[i].t){ restore(L,R,t);t--; } while(t<d[i].t){ t++;update(L,R,t); } while(R>d[i].r){ work(R);R--; } while(R<d[i].r){ R++;work(R); } while(L<d[i].l){ work(L);L++; } while(L>d[i].l){ L--;work(L); } ans[d[i].biao]=sum; if(d[i].flag) ans[d[i].biao]+=(W[cont[a[d[i].lca]]+1]*V[a[d[i].lca]]); } for(int i=1;i<=u;i++) printf("%lld\n",ans[i]); return 0; }