poj3237tree【樹鏈剖分入門題+線段樹】
阿新 • • 發佈:2019-02-03
休息了兩天,今天開始做樹鏈剖分,除了模板長以外,還是挺好理解的。就只是線段樹+剖分獨特的函式,然後樹鏈剖分所用的陣列有點多,沒了。其中需要注意的一個點是“鏈”(路徑)不一定是從根節點到葉子節點的,輕兒子這個點它也有重兒子啊啊啊。
再說這個題,單點更新,區間取相反數,區間求最大值。
/*********** poj3237 2015.1.23 2504K 657MS C++ 6396B ***********/ #include <iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=101010+5; const int maxm=maxn+maxn; struct EDGENODE { int to,w,next; }edges[maxm]; int head[maxn],edge; inline void init(){ edge=0; memset(head,-1,sizeof(head)); } inline void addedge(int u,int v,int w) { edges[edge].w=w,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++; edges[edge].w=w,edges[edge].to=u,edges[edge].next=head[v],head[v]=edge++; } int que[maxn],son[maxn],idx[maxn],dep[maxn],siz[maxn],belong[maxn],fa[maxn],top[maxn],len[maxn],sump[maxn],seg[maxn],wei[maxn]; int l,r,ans,cnt,n; bool vis[maxn]; char cmd[22]; void split() { memset(dep,-1,sizeof(dep)); l=0; dep[que[r=1]=1]=0; fa[1]=-1; wei[1]=0; while(l<r) { int u=que[++l]; vis[u]=false; for(int i=head[u];i!=-1;i=edges[i].next) { int v=edges[i].to; int w=edges[i].w; if(dep[v]==-1) { dep[que[++r]=v]=dep[u]+1; fa[v]=u; wei[v]=w; } } } cnt=0; for(int i=n;i>0;i--) { int u=que[i],p=-1; siz[u]=1; son[u]=p; for(int k=head[u];k!=-1;k=edges[k].next) { int v=edges[k].to; if(vis[v]) { siz[u]+=siz[v]; if(p==-1||siz[v]>siz[p]) { son[u]=v; p=v; } } } if(p==-1) { idx[u]=len[++cnt]=1; belong[top[cnt]=u]=cnt; } else { idx[u]=++len[belong[u]=belong[p]]; top[belong[u]]=u; } vis[u]=true; } } const int INF=0x3f3f3f3f; struct SegmentTree { int num[maxn]; struct Tree { int l,r,max,min; bool neg; }; Tree tree[maxn*4]; void push_down(int root) { if(tree[root].neg) { if(tree[root].l!=tree[root].r) { tree[root<<1].neg^=1; tree[root<<1|1].neg^=1; swap(tree[root<<1].max,tree[root<<1].min); swap(tree[root<<1|1].max,tree[root<<1|1].min); tree[root<<1].max*=-1; tree[root<<1].min*=-1; tree[root<<1|1].max*=-1; tree[root<<1|1].min*=-1; } } tree[root].neg=0; } void push_up(int root) { tree[root].max=max(tree[root<<1].max,tree[root<<1|1].max); tree[root].min=min(tree[root<<1].min,tree[root<<1|1].min); } void build(int root,int l,int r) { tree[root].l=l; tree[root].r=r; tree[root].neg=0; if(tree[root].l==tree[root].r) { tree[root].max=num[l]; tree[root].min=num[l]; tree[root].neg=0; return; } int mid=(l+r)/2; build(root<<1,l,mid); build(root<<1|1,mid+1,r); push_up(root); } void update(int root,int pos,int val) { if(tree[root].l==tree[root].r) { tree[root].max=val; tree[root].min=val; return; } push_down(root); int mid=(tree[root].l+tree[root].r)/2; if(pos<=mid)update(root<<1,pos,val); else update(root<<1|1,pos,val); push_up(root); } int query(int root,int L,int R) { if(L<=tree[root].l&&R>=tree[root].r) return tree[root].max; push_down(root); int mid=(tree[root].l+tree[root].r)/2,ret=-INF; if(L<=mid) ret=max(ret,query(root<<1,L,R)); if(R>mid) ret=max(ret,query(root<<1|1,L,R)); push_up(root); return ret; } void nega(int root,int L,int R) { if(L<=tree[root].l&&R>=tree[root].r) { tree[root].neg^=1; swap(tree[root].max,tree[root].min); tree[root].max*=-1; tree[root].min*=-1; return; } push_down(root); int mid=(tree[root].l+tree[root].r)/2; if(L<=mid) nega(root<<1,L,R); if(R>mid) nega(root<<1|1,L,R); push_up(root); } void debug(int root) { printf("rt=%d [%d~%d] min=%d max=%d neg=%d\n",root,tree[root].l,tree[root].r,tree[root].min ,tree[root].max,(int)tree[root].neg); if(tree[root].l==tree[root].r) return; debug(root<<1); debug(root<<1|1); } }tr; int find(int va,int vb) { int f1=top[belong[va]],f2=top[belong[vb]],tmp=-INF; while(f1!=f2) { if(dep[f1]<dep[f2]) { swap(f1,f2); swap(va,vb); } tmp=max(tmp,tr.query(1,seg[f1],seg[va])); va=fa[f1]; f1=top[belong[va]]; } if(va==vb) return tmp; if(dep[va]>dep[vb]) swap(va,vb); return max(tmp,tr.query(1,seg[son[va]],seg[vb])); } void gao(int va,int vb) { int f1=top[belong[va]],f2=top[belong[vb]]; while(f1!=f2) { if(dep[f1]<dep[f2]) { swap(f1,f2); swap(va,vb); } tr.nega(1,seg[f1],seg[va]); va=fa[f1]; f1=top[belong[va]]; } if(va==vb) return; if(dep[va]>dep[vb]) swap(va,vb); tr.nega(1,seg[son[va]],seg[vb]); } int d[maxn][3]; int main() { // freopen("cin.txt","r",stdin); int T; scanf("%d",&T); while(T--) { init(); scanf("%d",&n); for(int i=1;i<n;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); d[i][0]=a; d[i][1]=b; d[i][2]=c; addedge(a,b,c); } split(); sump[0]=0; for(int i=1;i<=cnt;i++) sump[i]=sump[i-1]+len[i]; for(int i=1;i<=n;i++) { seg[i]=sump[belong[i]]-idx[i]+1; tr.num[seg[i]]=wei[i]; } tr.build(1,1,n); while(scanf("%s",cmd)) { if(cmd[0]=='D') break; int x,y; scanf("%d%d",&x,&y); if(cmd[0]=='Q') printf("%d\n",find(x,y)); if(cmd[0]=='C') { if(fa[d[x][1]]==d[x][0]) tr.update(1,seg[d[x][1]],y); else tr.update(1,seg[d[x][0]],y); } if(cmd[0]=='N') gao(x,y); } } return 0; }