[bzoj2816][ZJOI2012]网络(LCT,splay)

传送门

题解

话说以前还真没见过用LCT只维护一条链的……好像除了树点涂色那题……

先看一下题目规定的两个性质

  1. 对于任意节点连出去的边中,相同颜色的边不超过两条。
  2. 图中不存在同色的环,同色的环指相同颜色的边构成的环。

很明显了,同一种颜色肯定是由几条链组成的(虽然我根本没有发现)

然后又要查询边权和维护路径……直接上LCT吧

然后颜色数很少啊……每一个颜色开一个LCT好了

更改权值的话在每一个LCT上splay一下

修改颜色的话在原来的LCT中cut,新的LCT中link

查询路径直接split出来

然后差不多就这样了

  1 //minamoto
  2 #include<cstdio>
  3 #include<map>
  4 #include<iostream>
  5 using std::swap;
  6 using std::map;
  7 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
  8 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
  9 char buf[1<<21],*p1=buf,*p2=buf;
 10 inline int read(){
 11     #define num ch-‘0‘
 12     char ch;bool flag=0;int res;
 13     while(!isdigit(ch=getc()))
 14     (ch==‘-‘)&&(flag=true);
 15     for(res=num;isdigit(ch=getc());res=res*10+num);
 16     (flag)&&(res=-res);
 17     #undef num
 18     return res;
 19 }
 20 const int N=10005;
 21 int n,m,val[N],c,k;
 22 struct link_cut_tree{
 23     int fa[N],ch[N][2],rev[N],mx[N],cnt[N],s[N],top;
 24     inline bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
 25     inline void pushup(int x){
 26         mx[x]=val[x];int l=ch[x][0],r=ch[x][1];
 27         if(l) cmax(mx[x],mx[l]);
 28         if(r) cmax(mx[x],mx[r]);
 29     }
 30     inline void pushdown(int x){
 31         if(x&&rev[x]){
 32             swap(ch[x][0],ch[x][1]);
 33             rev[ch[x][0]]^=1,rev[ch[x][1]]^=1;
 34             rev[x]=0;
 35         }
 36     }
 37     void rotate(int x){
 38         int y=fa[x],z=fa[y],d=ch[y][1]==x;
 39         if(!isroot(y)) ch[z][ch[z][1]==y]=x;
 40         fa[x]=z,fa[y]=x,fa[ch[x][d^1]]=y,ch[y][d]=ch[x][d^1],ch[x][d^1]=y,pushup(y);
 41     }
 42     void splay(int x){
 43         s[top=1]=x;for(int i=x;!isroot(i);i=fa[i]) s[++top]=fa[i];
 44         while(top) pushdown(s[top--]);
 45         for(int y=fa[x],z=fa[y];!isroot(x);y=fa[x],z=fa[y]){
 46             if(!isroot(y))
 47             ((ch[y][1]==x)^(ch[z][1]==y))?rotate(x):rotate(y);
 48             rotate(x);
 49         }
 50         pushup(x);
 51     }
 52     void access(int x){
 53         for(int y=0;x;x=fa[y=x])
 54         splay(x),ch[x][1]=y,pushup(x);
 55     }
 56     void makeroot(int x){
 57         access(x),splay(x),rev[x]^=1;
 58     }
 59     void split(int x,int y){
 60         makeroot(x),access(y),splay(y);
 61     }
 62     inline void link(int x,int y){
 63         ++cnt[x],++cnt[y],makeroot(x),fa[x]=y,splay(x);
 64     }
 65     inline void cut(int x,int y){
 66         --cnt[x],--cnt[y],split(x,y),fa[x]=ch[y][0]=0,pushup(y);
 67     }
 68     int findroot(int x){
 69         access(x),splay(x),pushdown(x);
 70         while(ch[x][0]) pushdown(x=ch[x][0]);
 71         return x;
 72     }
 73     inline int query(int x,int y){
 74         split(x,y);return mx[y];
 75     }
 76 }lct[15];
 77 struct edge{
 78     int u,v;
 79     inline bool operator <(const edge &b)const
 80     {return u<b.u||(u==b.u&&v<b.v);}
 81 };
 82 map<edge,int> mp;
 83 int main(){
 84     //freopen("testdata.in","r",stdin);
 85     n=read(),m=read(),c=read(),k=read();
 86     for(int i=1;i<=n;++i) val[i]=read();
 87     for(int i=1;i<=m;++i){
 88         int u=read(),v=read(),w=read();
 89         edge e1=(edge){u,v},e2=(edge){v,u};
 90         mp[e1]=mp[e2]=w;
 91         lct[w].link(u,v);
 92     }
 93     while(k--){
 94         int opt=read();
 95         switch(opt){
 96             case 0:{
 97                 int x=read(),w=read();
 98                 val[x]=w;
 99                 for(int i=0;i<c;++i) lct[i].splay(x);
100                 break;
101             }
102             case 1:{
103                 int u=read(),v=read(),w=read();
104                 edge a=(edge){u,v},b=(edge){v,u};
105                 if(!mp.count(a)){puts("No such edge.");continue;}
106                 int x=mp[a];
107                 if(x==w){puts("Success.");continue;}
108                 if(lct[w].cnt[u]>=2||lct[w].cnt[v]>=2){puts("Error 1.");continue;}
109                 if(lct[w].findroot(u)==lct[w].findroot(v)){puts("Error 2.");continue;}
110                 puts("Success.");
111                 lct[x].cut(u,v),lct[w].link(u,v);
112                 mp[a]=mp[b]=w;
113                 break;
114             }
115             case 2:{
116                 int w=read(),u=read(),v=read();
117                 if(lct[w].findroot(u)!=lct[w].findroot(v)){puts("-1");continue;}
118                 printf("%d\n",lct[w].query(u,v));
119                 break;
120             }
121         }
122     }
123     return 0;
124 }

原文地址:https://www.cnblogs.com/bztMinamoto/p/9425443.html

时间: 2024-08-30 09:39:18

[bzoj2816][ZJOI2012]网络(LCT,splay)的相关文章

ZJOI2012 网络——LCT相关题目

有一个无向图G,每个点有个权值,每条边有一个颜色.这个无向图满足以下两个条件: 对于任意节点连出去的边中,相同颜色的边不超过两条. 图中不存在同色的环,同色的环指相同颜色的边构成的环. 在这个图上,你要支持以下三种操作: 修改一个节点的权值. 修改一条边的颜色. 查询由颜色c的边构成的图中,所有可能在节点u到节点v之间的简单路径上的节点的权值的最大值. https://daniu.luogu.org/problem/show?pid=2173 -by luogu 对每个颜色建LCT,对error

luoguP2173 [ZJOI2012]网络 LCT

链接 luogu 思路 颜色很少,开10个lct分别维护 if (Hash.count(make_pair(u, v)) && Hash[make_pair(u, v)] == col) {puts("Success.");continue;} 这一行的代码调了半天. 代码 #include <bits/stdc++.h> #define ls c[x][0] #define rs c[x][1] using namespace std; const int

bzoj 2816: [ZJOI2012]网络(splay)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2816 [题意] 给定一个无向图,满足条件:从一个节点出发的同色边不超过2条,且不存在同色环.要求提供修改节点权值,修改边的颜色,查询同色边c构成的图中u->v路径上节点的最大权值. [思路] 根据满足的条件,可以判断同色的图构成了若干条一条链. 考虑使用splay维护这些链: 对于每个图上的点建C个splay结点.这里需要splay提供将结点u旋转到根的操作,所以需要维护一个fa指针

[ZJOI2012]网络

[ZJOI2012]网络 题目 思路 显然,这是一道lct裸题.因为颜色不多,所以对于每一种颜色的边我们都建一个lct即可.(我这里是用 (颜色×n+点的标号) 表示每一种颜色lct) 操作0 因为我们对于每一种颜色的边都建了一个lct所以,我们对于每一种颜色的边都update一次.(虽然很暴力,但跑得过) 操作1 1.其实对于判断边不存在的情况,我们可以用临接矩阵来存,开一个bool数组10000*10000 128M还是开得下的.这样节约了很多时间(其实是我懒得想其它方法判断). 2.错误1

AC日记——[ZJOI2012]网络 bzoj 2816

2816 思路: 多个LCT: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 10005 #define ll long long int val[maxn]; struct LinkCutTreeType { int f[maxn],Max[maxn],ch[maxn][2],rev[maxn],sta[maxn],top,cnt[maxn]; void updata(int now) { Max[now]=va

BZOJ 2843: 极地旅行社 lct splay

http://www.lydsy.com/JudgeOnline/problem.php?id=2843 https://blog.csdn.net/clove_unique/article/details/50992341 和之前那道题lct求两点距离用lca不同,这道题因为给的边的两个端点是没有顺序的(没法直接按照给的点直接将某个点连到树上),所以bridge需要区间翻转的操作,因为splay维护的是链,所以区间翻转相当于将叶子变成了根,根变成叶子(链翻转过来),然后再把此时的根(x)连到y

洛谷 2173 [ZJOI2012]网络

[题解] 明显的LCT模板题,c种颜色就开c棵LCT好了.. 1 #include<cstdio> 2 #include<algorithm> 3 #define N 500010 4 #define C 20 5 #define rg register 6 #define ls (son[c][u][0]) 7 #define rs (son[c][u][1]) 8 using namespace std; 9 int n,m,c,k,opt,x,y,w,top; 10 int

P2173 [ZJOI2012]网络

\(\color{#0066ff}{ 题目描述 }\) 有一个无向图G,每个点有个权值,每条边有一个颜色.这个无向图满足以下两个条件: 对于任意节点连出去的边中,相同颜色的边不超过两条. 图中不存在同色的环,同色的环指相同颜色的边构成的环. 在这个图上,你要支持以下三种操作: 修改一个节点的权值. 修改一条边的颜色. 查询由颜色c的边构成的图中,所有可能在节点u到节点v之间的简单路径上的节点的权值的最大值. \(\color{#0066ff}{输入格式}\) 输入文件network.in的第一行

BZOJ 3091: 城市旅行 [LCT splay 期望]

3091: 城市旅行 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1454  Solved: 483[Submit][Status][Discuss] Description Input Output Sample Input 4 5 1 3 2 5 1 2 1 3 2 4 4 2 4 1 2 4 2 3 4 3 1 4 1 4 1 4 Sample Output 16/3 6/1 HINT 对于所有数据满足 1<=N<=50,000 1&l