BZOJ 2157 旅行(树链剖分码农题)
Posted freeloop
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 2157 旅行(树链剖分码农题)相关的知识,希望对你有一定的参考价值。
写了5KB,1发AC。。。
题意:给出一颗树,支持5种操作。
1.修改某条边的权值。2.将u到v的经过的边的权值取负。3.求u到v的经过的边的权值总和。4.求u到v的经过的边的权值最大值。5.求u到v经过的边的权值最小值。
基于边权的树链剖分,放在线段树上变成了区间维护问题了,线段树维护4个量min,max,sum,tag就可以了。
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <bitset> # include <set> # include <cmath> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi acos(-1.0) # define eps 1e-8 # define MOD 30031 # define INF 1000000000 # define mem(a,b) memset(a,b,sizeof(a)) # define FOR(i,a,n) for(int i=a; i<=n; ++i) # define FO(i,a,n) for(int i=a; i<n; ++i) # define bug puts("H"); # define lch p<<1,l,mid # define rch p<<1|1,mid+1,r # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; int Scan() { int 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; } const int N=20005; //Code begin... struct Edge{int p, next;}edge[N<<1]; struct Seg{int sum, ma, mi;}seg[N<<3]; bool tag[N<<3]; int head[N], cnt=1, E[N][3], n; int top[N], fa[N], deep[N], num[N], p[N], fp[N], son[N], pos; void add_edge(int u, int v){ edge[cnt].p=v; edge[cnt].next=head[u]; head[u]=cnt++; } void init(){mem(son,-1); pos=1;} void dfs1(int u, int pre, int d){ deep[u]=d; fa[u]=pre; num[u]=1; for (int i=head[u]; i; i=edge[i].next) { int v=edge[i].p; if (v==pre) continue; dfs1(v,u,d+1); num[u]+=num[v]; if (son[u]==-1||num[v]>num[son[u]]) son[u]=v; } } void getpos(int u, int sp){ top[u]=sp; p[u]=pos++; fp[p[u]]=u; if (son[u]==-1) return ; getpos(son[u],sp); for (int i=head[u]; i; i=edge[i].next) { int v=edge[i].p; if (v!=son[u]&&v!=fa[u]) getpos(v,v); } } void push_up(int p){ seg[p].sum=seg[p<<1].sum+seg[p<<1|1].sum; seg[p].ma=max(seg[p<<1].ma,seg[p<<1|1].ma); seg[p].mi=min(seg[p<<1].mi,seg[p<<1|1].mi); } void push_down(int p){ if (!tag[p]) return ; seg[p].sum=-seg[p].sum; swap(seg[p].ma,seg[p].mi); seg[p].ma=-seg[p].ma; seg[p].mi=-seg[p].mi; tag[p<<1]^=tag[p]; tag[p<<1|1]^=tag[p]; tag[p]=false; } void Update(int p, int l, int r, int L, int val){ push_down(p); if (L>r||L<l) return ; if (L==l&&L==r) seg[p].ma=seg[p].mi=seg[p].sum=val; else { int mid=(l+r)>>1; Update(lch,L,val); Update(rch,L,val); push_up(p); } } void Inv(int p, int l, int r, int L, int R){ push_down(p); if (L>r||R<l) return ; if (L<=l&&R>=r) tag[p]^=1, push_down(p); else { int mid=(l+r)>>1; Inv(lch,L,R); Inv(rch,L,R); push_up(p); } } int Query_Max(int p, int l, int r, int L, int R){ push_down(p); if (L>r||R<l) return -INF; if (L<=l&&R>=r) return seg[p].ma; int mid=(l+r)>>1; return max(Query_Max(lch,L,R),Query_Max(rch,L,R)); } int Query_Min(int p, int l, int r, int L, int R){ push_down(p); if (L>r||R<l) return INF; if (L<=l&&R>=r) return seg[p].mi; int mid=(l+r)>>1; return min(Query_Min(lch,L,R),Query_Min(rch,L,R)); } int Query_Sum(int p, int l, int r, int L, int R){ push_down(p); if (L>r||R<l) return 0; if (L<=l&&R>=r) return seg[p].sum; int mid=(l+r)>>1; return Query_Sum(lch,L,R)+Query_Sum(rch,L,R); } int Sol(int u, int v, int flag){ int f1=top[u], f2=top[v], ans; if (flag==2) ans=0; else if (flag==3) ans=-INF; else ans=INF; while (f1!=f2) { if (deep[f1]<deep[f2]) swap(f1,f2), swap(u,v); if (flag==1) Inv(1,1,n,p[f1],p[u]); else if (flag==2) ans+=Query_Sum(1,1,n,p[f1],p[u]); else if (flag==3) ans=max(ans,Query_Max(1,1,n,p[f1],p[u])); else ans=min(ans,Query_Min(1,1,n,p[f1],p[u])); u=fa[f1]; f1=top[u]; } if (u==v) return ans; if (deep[u]>deep[v]) swap(u,v); if (flag==1) {Inv(1,1,n,p[son[u]],p[v]); return 0;} else if (flag==2) return ans+Query_Sum(1,1,n,p[son[u]],p[v]); else if (flag==3) return max(ans,Query_Max(1,1,n,p[son[u]],p[v])); else return min(ans,Query_Min(1,1,n,p[son[u]],p[v])); } int main () { int m, x, y; char s[5]; scanf("%d",&n); init(); FO(i,1,n) scanf("%d%d%d",&E[i][0],&E[i][1],&E[i][2]), ++E[i][0], ++E[i][1], add_edge(E[i][0],E[i][1]), add_edge(E[i][1],E[i][0]); dfs1(1,0,0); getpos(1,1); FO(i,1,n) { if (deep[E[i][0]]>deep[E[i][1]]) swap(E[i][0],E[i][1]); Update(1,1,n,p[E[i][1]],E[i][2]); } scanf("%d",&m); while (m--) { scanf("%s%d%d",s,&x,&y); if (!strcmp(s,"C")) Update(1,1,n,p[E[x][1]],y); else if (!strcmp(s,"N")) ++x, ++y, Sol(x,y,1); else if (!strcmp(s,"SUM")) ++x, ++y, printf("%d\n",Sol(x,y,2)); else if (!strcmp(s,"MAX")) ++x, ++y, printf("%d\n",Sol(x,y,3)); else ++x, ++y, printf("%d\n",Sol(x,y,4)); } return 0; }
以上是关于BZOJ 2157 旅行(树链剖分码农题)的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 2157 「国家集训队」旅游(树链剖分,线段树,边权转点权)BZOJ计划
BZOJ 2157 「国家集训队」旅游(树链剖分,线段树,边权转点权)BZOJ计划