链接:
http://www.spoj.pl/problems/QTREE/
http://poj.org/problem?id=3237
题意:一棵树,两种更新操作,改变一条边的边权,将a ->b路径上的所有边权取反,询问一条路径上的最大边权
都是典型的树链剖分,下面一题是上面的加强版,还要在树上进行成段更新,其实也不难。
只是区间还要再记录一个最小值,因为取反操作的话会使得区间的最大值和最小值互换。
然后就是树链剖分的老套路,如果是重链,在线段树中更新,否则直接改变边权。
线段树中下放懒惰标记的时候写漏了,调了许久,囧爆了。。。。
好像还可以用动态树实现吧,概念都看懂了,只是没实践过,改天去学了再贴上来吧
下面是这两题的代码,我的代码有点搓 - -,观看请慎重,以免伤了眼*_*
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|1 const 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; } /* 1 3 1 2 1 2 3 2 QUERY 1 2 CHANGE 1 3 QUERY 1 2 DONE 1 3 1 7 1 2 1 1 3 2 2 4 3 2 5 4 3 6 5 3 7 6 Query 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|1 const 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; }