連結:
http://www.spoj.pl/problems/QTREE/
http://poj.org/problem?id=3237
題意:一棵樹,兩種更新操作,改變一條邊的邊權,將a ->b路徑上的所有邊權取反,詢問一條路徑上的最大邊權
都是典型的樹鏈剖分,下面一題是上面的加強版,還要在樹上進行成段更新,其實也不難。
只是區間還要再記錄一個最小值,因為取反操作的話會使得區間的最大值和最小值互換。
然後就是樹鏈剖分的老套路,如果是重鏈,線上段樹中更新,否則直接改變邊權。
線段樹中下放懶惰標記的時候寫漏了,調了許久,囧爆了。。。。
好像還可以用動態樹實現吧,概念都看懂了,只是沒實踐過,改天去學了再貼上來吧
下面是這兩題的代碼,My Code有點搓 - -,觀看請謹慎,以免傷了眼*_*
spoj 375 query on a tree
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1const int maxn = 20010;const int inf = ~0u>>2;int M[maxn<<2];struct node{ int s,t,w,next;}edge[maxn*2];int E,n;int size[maxn] , fa[maxn] , heavy[maxn] , head[maxn] , dep[maxn] , rev[maxn] , num[maxn] , cost[maxn];int Seg_size;inline void Max(int &x,int y){if(x<y) x=y;}int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}void add_edge(int s,int t,int w){ edge[E].w=w; edge[E].s=s; edge[E].t=t; edge[E].next=head[s]; head[s]=E++;}void dfs(int u,int f){ int mx=-1,e=-1; size[u]=1; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].t; if(v==f) continue; dep[v]=dep[u]+1; rev[v]=i^1; dfs(v,u); size[u]+=size[v]; if(size[v]>mx) { mx=size[v]; e=i; } } heavy[u]=e; if(e!=-1) fa[edge[e].t]=u;}inline void pushup(int rt){ M[rt]=max(M[rt<<1],M[rt<<1|1]);}void build(int l,int r,int rt){ M[rt]=inf; if(l==r){ return ; } int m=(l+r)>>1; build(lson); build(rson);}void update(int p,int val,int l,int r,int rt){ if(l==r){ M[rt]=val; return ; } int m=(l+r)>>1; if(p<=m) update(p,val,lson); else update(p,val,rson); pushup(rt);}int query(int L,int R,int l,int r,int rt){ if(L<=l&&r<=R){ return M[rt]; } int m=(l+r)>>1; int ret=0; if(L<=m) ret=max(ret,query(L,R,lson)); if(R>m) ret=max(ret,query(L,R,rson)); return ret;}void prepare(){ build(1,n-1,1); memset(num,-1,sizeof(num)); dep[0]=0;Seg_size=0; for(int i=0;i<n;i++) fa[i]=i; dfs(0,0); for(int i=0;i<n;i++) { if(heavy[i]==-1) { int pos=i; while(pos && edge[heavy[edge[rev[pos]].t]].t == pos) { int t=rev[pos]; num[t]=num[t^1]=++Seg_size; update(Seg_size,edge[t].w,1,n-1,1); pos=edge[t].t; } } }}void change(int edge_id,int val){ if(num[edge_id]==-1) edge[edge_id].w=edge[edge_id^1].w=val; else update(num[edge_id],val,1,n-1,1);}int calc(int u,int lca){ int ans=-inf;int vi=0; while(u!=lca) { vi++; if(vi==10) break; int r=rev[u]; if(num[r]==-1) Max(ans,edge[r].w),u=edge[r].t; else { int p=fa[u]; if(dep[p] < dep[lca]) p=lca; int l=num[r]; int r=num[heavy[p]]; Max(ans,query(l,r,1,n-1,1)); u=p; } } return ans;}int lca(int u,int v){ while(1) { int a=find(u),b=find(v); if(a==b) return dep[u] < dep[v] ? u : v;//a,b在同一條重鏈上 else if(dep[a]>=dep[b]) u=edge[rev[a]].t; else v=edge[rev[b]].t; }}int solve(int u,int v){ int p=lca(u,v); return max(calc(u,p),calc(v,p));}int main(){ int t,i,a,b,c; scanf("%d",&t); while(t--) { memset(head,-1,sizeof(head)); E=0; scanf("%d",&n); for(i=0;i<n-1;i++) { scanf("%d%d%d",&a,&b,&c);a--;b--; add_edge(a,b,c); add_edge(b,a,c); } prepare(); char op[20]; while(scanf("%s",op)!=EOF && strcmp(op,"DONE")) { if(op[0]=='C') { scanf("%d%d",&a,&c); change((a-1)*2,c); } else { scanf("%d%d",&a,&b); printf("%d\n",solve(a-1,b-1)); } } } return 0;}/*131 2 12 3 2QUERY 1 2CHANGE 1 3QUERY 1 2DONE13171 2 11 3 22 4 32 5 43 6 53 7 6Query 1 7*/
poj 3237
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1const int maxn = 100010;const int inf = ~0u>>2;int M[maxn<<2];int Mi[maxn<<2];int col[maxn<<2];struct node{int s,t,w,next;}edge[maxn*2];int E,n;int size[maxn] , fa[maxn] , heavy[maxn] , head[maxn] , dep[maxn] , rev[maxn] , num[maxn] , cost[maxn];int Seg_size;inline void Max(int &x,int y){if(x<y) x=y;}inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a>b?b:a;}int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}void add_edge(int s,int t,int w){edge[E].w=w;edge[E].s=s;edge[E].t=t;edge[E].next=head[s];head[s]=E++;}void dfs(int u,int f){int mx=-1,e=-1;size[u]=1;for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].t;if(v==f) continue;dep[v]=dep[u]+1;rev[v]=i^1;dfs(v,u);size[u]+=size[v];if(size[v]>mx){mx=size[v];e=i;}}heavy[u]=e;if(e!=-1) fa[edge[e].t]=u;}void build(int l,int r,int rt){Mi[rt]=inf;M[rt]=-inf;col[rt]=0;if(l==r){return ;}int m=(l+r)>>1;build(lson);build(rson);}inline void pushup(int rt){M[rt]=max(M[rt<<1],M[rt<<1|1]);Mi[rt]=min(Mi[rt<<1],Mi[rt<<1|1]);}void make(int rt){int tmp=Mi[rt];Mi[rt]=-M[rt];M[rt]=-tmp;}void pushdown(int rt){if(col[rt]){ col[rt<<1]^=1; make(rt<<1); col[rt<<1|1]^=1; make(rt<<1|1); col[rt]=0;//很久沒寫線段樹,連這個都忘了,囧}}void update(int p,int val,int l,int r,int rt){if(l==r){ Mi[rt]=M[rt]=val; return ;}pushdown(rt);int m=(l+r)>>1;if(p<=m) update(p,val,lson);else update(p,val,rson);pushup(rt);}void justdoit(int L,int R,int l,int r,int rt){//printf("L=%d R=%d l=%d r=%d\n",L,R,l,r);if(L<=l&&r<=R){col[rt]^=1;make(rt);return ;}pushdown(rt);int m=(l+r)>>1;if(L<=m) justdoit(L,R,lson);if(R>m) justdoit(L,R,rson);pushup(rt);}int query(int L,int R,int l,int r,int rt){if(L<=l&&r<=R){return M[rt];}pushdown(rt);int m=(l+r)>>1;int ret=-inf;if(L<=m) ret=max(ret,query(L,R,lson));if(R>m) ret=max(ret,query(L,R,rson));return ret;}void prepare(){build(1,n-1,1);memset(num,-1,sizeof(num));dep[0]=0;Seg_size=0;for(int i=0;i<n;i++) fa[i]=i;dfs(0,0);for(int i=0;i<n;i++){if(heavy[i]==-1){int pos=i;while(pos && edge[heavy[edge[rev[pos]].t]].t == pos){int t=rev[pos];num[t]=num[t^1]=++Seg_size;update(Seg_size,edge[t].w,1,n-1,1);pos=edge[t].t;}}}}void change(int edge_id,int val){if(num[edge_id]==-1) edge[edge_id].w=edge[edge_id^1].w=val;else update(num[edge_id],val,1,n-1,1);}int calc(int u,int lca){int ans=-inf; while(u!=lca){int r=rev[u];if(num[r]==-1) Max(ans,edge[r].w),u=edge[r].t;else {int p=fa[u];if(dep[p] < dep[lca]) p=lca;int l=num[r];int r=num[heavy[p]];Max(ans,query(l,r,1,n-1,1));u=p;}}return ans;}void gao(int u,int lca){while(u!=lca){int r=rev[u];if(num[r]==-1) edge[r].w=edge[r^1].w=-edge[r].w,u=edge[r].t;else{int p=fa[u];if(dep[p] < dep[lca]) p=lca;int l=num[r];int r=num[heavy[p]];//printf("l=%d r=%d\n",l,r);justdoit(l,r,1,n-1,1);u=p;}}}int lca(int u,int v){while(1){int a=find(u),b=find(v);if(a==b) return dep[u] < dep[v] ? u : v;//a,b在同一條重鏈上else if(dep[a]>=dep[b]) u=edge[rev[a]].t;else v=edge[rev[b]].t;}}int solve(int u,int v){int p=lca(u,v);return max(calc(u,p),calc(v,p));}void sol(int u,int v){int p=lca(u,v);//printf("p=%d\n",p);gao(u,p);gao(v,p);}int main(){int t,i,a,b,c;scanf("%d",&t);while(t--){memset(head,-1,sizeof(head));E=0;scanf("%d",&n);for(i=0;i<n-1;i++){scanf("%d%d%d",&a,&b,&c);a--;b--;add_edge(a,b,c);add_edge(b,a,c);}prepare();char op[20];while(scanf("%s",op)!=EOF && strcmp(op,"DONE")){if(op[0]=='C'){scanf("%d%d",&a,&c);change((a-1)*2,c);}else if(op[0]=='N'){scanf("%d%d",&a,&b);if(a==b) while(1);sol(a-1,b-1);}else {scanf("%d%d",&a,&b);if(a==b) while(1);printf("%d\n",solve(a-1,b-1));}}}return 0;}