【BZOJ 1180】OTOCI【LCT】&【树链剖分+并查集】
2017-05-07 16:22
393 查看
Description
给出n个结点以及每个点初始时对应的权值wi。起始时点与点之间没有连边。有3类操作:1、bridge A B:询问结点A与结点B是否连通。如果是则输出“no”。否则输出“yes”,并且在结点A和结点B之间连一条无向边。
2、penguins A X:将结点A对应的权值wA修改为X。
3、excursion A B:如果结点A和结点B不连通,则输出“impossible”。否则输出结点A到结点B的路径上的点对应的权值的和。
给出q个操作,要求在线处理所有操作。数据范围:1<=n<=30000, 1<=q<=300000, 0<=wi<=1000。
Input
第一行包含一个整数n(1<=n<=30000),表示节点的数目。第二行包含n个整数,第i个整数表示第i个节点初始时对应的权值。第三行包含一个整数q(1<=n<=300000),表示操作的数目。以下q行,每行包含一个操作,操作的类别见题目描述。任意时刻每个节点对应的权值都是1到1000的整数。Output
输出所有bridge操作和excursion操作对应的输出,每个一行。题解
一、LCT
本题最基本的方法#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 60010 #define lson node[o].ls #define rson node[o].rs struct LCT{ struct Node{ int idx,fa,ls,rs,path_fa; } node ; int cnt,pos ,a ,tot ; bool ch ; inline void maintain(int o) { if(ch[o]) { ch[o] = false; ch[lson] = !ch[lson]; ch[rson] = !ch[rson]; swap(lson,rson); } tot[o] = tot[lson] + tot[rson] + a[node[o].idx]; } void l_rotate(int o) { int y = node[o].fa; node[o].path_fa = node[y].path_fa; node[y].path_fa = 0; node[y].rs = lson; int tmp = tot[y]; tot[y] = tot[y] - tot[o] + tot[lson]; tot[o] = tmp; if(lson) node[lson].fa = y; node[o].fa = node[y].fa; if(node[y].fa) { if(y == node[node[y].fa].ls) node[node[y].fa].ls = o; else node[node[y].fa].rs = o; } node[y].fa = o; node[o].ls = y; } void r_rotate(int o) { int y = node[o].fa; node[o].path_fa = node[y].path_fa; node[y].path_fa = 0; node[y].ls = rson; int tmp = tot[y]; tot[y] = tot[y] - tot[o] + tot[rson]; tot[o] = tmp; if(rson) node[rson].fa = y; node[o].fa = node[y].fa; if(node[y].fa) { if(y == node[node[y].fa].ls) node[node[y].fa].ls = o; else node[node[y].fa].rs = o; } node[y].fa = o; node[o].rs = y; } void splay(int o) { while(node[o].fa) { int pa = node[o].fa; maintain(pa); if(node[pa].ls) maintain(node[pa].ls); if(node[pa].rs) maintain(node[pa].rs); if(o == node[node[o].fa].ls) r_rotate(o); else l_rotate(o); } } void access(int o) { splay(o); maintain(o); int q = rson; rson = node[q].fa = 0; node[q].path_fa = o; maintain(o); for(q = node[o].path_fa;q;q = node[o].path_fa) { splay(q); maintain(q); int r = node[q].rs; node[r].fa = 0; node[r].path_fa = q; node[q].rs = o; node[o].fa = q; node[o].path_fa = 0; maintain(q); o = q; } splay(o); } int find_root(int o) { access(o); splay(o); maintain(o); while(lson) o = lson; splay(o); return o; } void evert(int o) { access(o); splay(o); ch[o] = !ch[o]; maintain(o); } void cut(int p,int q) { evert(p); access(q); splay(q); maintain(q); node[node[q].ls].fa = 0; node[q].ls = 0; maintain(q); } void link(int p,int q) { evert(p); splay(p); maintain(p); access(q); splay(q); maintain(q); node[p].ls = q; node[q].fa = p; maintain(p); } int sum(int p,int q) { evert(p); splay(p); maintain(p); access(q); splay(q); maintain(q); return tot[q]; } void change(int o,int d,int pre) { splay(o); tot[o] += d - pre; } void init() { cnt = 0; memset(pos,0,sizeof(pos)); tot[0] = 0; } void make_tree(int idx,int d) { a[idx] = d; int o = ++cnt; pos[idx] = o; node[o].fa = lson = rson = node[o].path_fa = 0; tot[o] = d; node[o].idx = idx; } int getroot(int idx) { return node[find_root(idx)].idx; } void add_edge(int x,int y) { link(pos[x],pos[y]); } void destory(int x,int y) { cut(pos[x],pos[y]); } int getsum(int x,int y) { return sum(pos[x],pos[y]); } void Change(int x,int d) { change(pos[x],d,a[x]); a[x] = d; } }T; int n,u,v,q; char str[20]; int main() { scanf("%d",&n); T.init(); for(int i = 1;i <= n;i++) { scanf("%d",&v); T.make_tree(i,v); } scanf("%d",&q); while(q--) { scanf("%s%d%d",str,&u,&v); if(str[0] == 'b') { if(T.getroot(u) == T.getroot(v)) puts("no"); else {puts("yes"); T.add_edge(u,v);} } else if(str[0] == 'p') T.Change(u,v); else { if(T.getroot(u) != T.getroot(v)) puts("impossible"); else printf("%d\n",T.getsum(u,v)); } } return 0; }
二、树链剖分+并查集
我个人更喜欢这一种,好写一点。考虑到本题没有删边操作,所以一开始将所有的添加边搞出来,确定树的形态(注意,可能是一棵森林,在树链剖分dfs的时候要注意)
然后再用并查集维护连通性即可。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 30100 #define M 300100 struct node{int to,next;}e[N<<2]; int head ,tot; int tid ,son ,fa ,top ,dep ,size ,Rank ; int n,a ,tim; bool vis ; void init() { tot = tim = 0; memset(head,0,sizeof(head)); memset(son,-1,sizeof(son)); memset(vis,false,sizeof(vis)); } void add_edge(int from,int to) { e[++tot].next = head[from]; head[from] = tot; e[tot].to = to; } void dfs1(int v,int pa,int deep) { dep[v] = deep; fa[v] = pa; size[v] = 1; vis[v] = 1; for(int i = head[v];i;i = e[i].next) if(e[i].to != pa) { dfs1(e[i].to,v,deep+1); size[v] += size[e[i].to]; if(son[v] == -1 || size[e[i].to] > size[son[v]]) son[v] = e[i].to; } } void dfs2(int v,int tp) { top[v] = tp; tid[v] = ++tim; Rank[tid[v]] = v; if(son[v] == -1) return; dfs2(son[v],tp); for(int i = head[v];i;i=e[i].next) if(e[i].to != son[v] && e[i].to != fa[v]) dfs2(e[i].to,e[i].to); } int f ; int find(int x) { return x == f[x] ? x : f[x] = find(f[x]);} #define lson o << 1 #define rson o << 1 | 1 int sum[N<<2]; void build(int o,int l,int r) { if(l == r) {sum[o] = a[Rank[l]]; return;} int mid = (l+r)>>1; build(lson,l,mid); build(rson,mid+1,r); sum[o] = sum[lson] + sum[rson]; } void update(int o,int l,int r,int pos,int v) { if(l == r) {sum[o] = v; return;} int mid = (l+r)>>1; if(pos <= mid) update(lson,l,mid,pos,v); else update(rson,mid+1,r,pos,v); sum[o] = sum[lson] + sum[rson]; } int query(int o,int l,int r,int ll,int rr) { if(ll <= l && rr >= r) return sum[o]; int mid = (l+r)>>1; int ans = 0; if(ll <= mid) ans += query(lson,l,mid,ll,rr); if(rr > mid) ans += query(rson,mid+1,r,ll,rr); return ans; } int Query(int x,int y) { int ans = 0; while(top[x] != top[y]) { if(dep[top[x]] < dep[top[y]]) swap(x,y); ans += query(1,1,n,tid[top[x]],tid[x]); x = fa[top[x]]; } if(dep[x] > dep[y]) swap(x,y); ans += query(1,1,n,tid[x],tid[y]); return ans; } int A[M],B[M],opt[M]; int m; char str[20]; int main() { init(); scanf("%d",&n); for(int i = 1;i <= n;i++) scanf("%d",&a[i]); scanf("%d",&m); for(int i = 1;i <= n;i++) f[i] = i; for(int i = 1;i <= m;i++) { scanf("%s%d%d",str,&A[i],&B[i]); if(str[0] == 'b') { opt[i] = 1; int x = find(A[i]),y = find(B[i]); if(x != y) { f[x] = y; add_edge(A[i],B[i]); add_edge(B[i],A[i]); } } if(str[0] == 'p') opt[i] = 2; if(str[0] == 'e') opt[i] = 3; } for(int i = 1;i <= n;i++) if(!vis[i]) dfs1(i,0,0),dfs2(i,i); build(1,1,n); for(int i = 1;i <= n;i++) f[i] = i; for(int i = 1;i <= m;i++) { if(opt[i] == 1) { int x = find(A[i]),y = find(B[i]); if(x != y) {puts("yes"); f[x] = y;} else puts("no"); } if(opt[i] == 2) update(1,1,n,tid[A[i]],B[i]); if(opt[i] == 3) { int x = find(A[i]),y = find(B[i]); if(x != y) puts("impossible"); else printf("%d\n",Query(A[i],B[i])); } } return 0; }
相关文章推荐
- 【BZOJ】1180: [CROATIAN2009]OTOCI & 2843: 极地旅行社(lct)
- BZOJ 1180: [CROATIAN2009]OTOCI [LCT]
- BZOJ1180 [CROATIAN2009]OTOCI 【LCT】
- [BZOJ1180][CROATIAN2009][LCT]OTOCI
- [bzoj2843&&bzoj1180]极地旅行社 (lct)
- bzoj 1180: [CROATIAN2009]OTOCI【LCT】
- BZOJ_1180_[CROATIAN2009]_OTOCI_(LCT)
- bzoj1180 [CROATIAN2009]OTOCI(详解LCT操作)
- BZOJ_1180_[CROATIAN2009]OTOCI_LCT
- [bzoj1180][CROATIAN2009]OTOCI_LCT
- 【bzoj1180】【CROATIAN2009】【OTOCI】【lct】
- bzoj1180 [CROATIAN2009]OTOCI(lct)
- BZOJ1180 [CROATIAN2009]OTOCI 【LCT】
- BZOJ 1180: [CROATIAN2009]OTOCI (LCT题解)
- bzoj 1180 [CROATIAN2009]OTOCI - LCT
- [BZOJ1180][CROATIAN2009]OTOCI(LCT)
- BZOJ 1180: [CROATIAN2009]OTOCI|动态树
- bzoj1180: [CROATIAN2009]OTOCI
- BZOJ1180 LCT模版
- bzoj3514 Codechef MARCH14 GERALD07加强版 LCT&&主席树