[ZJOI2012]网络

[ZJOI2012]网络

题目

思路

显然,这是一道lct裸题。因为颜色不多,所以对于每一种颜色的边我们都建一个lct即可。(我这里是用 (颜色×n+点的标号) 表示每一种颜色lct)

操作0

因为我们对于每一种颜色的边都建了一个lct所以,我们对于每一种颜色的边都update一次。(虽然很暴力,但跑得过)

操作1

1.其实对于判断边不存在的情况,我们可以用临接矩阵来存,开一个bool数组10000*10000 128M还是开得下的。这样节约了很多时间(其实是我懒得想其它方法判断)。

2.错误1,开一个degree记录每个点每一种颜色的边的度即可。

3.错误2,判断一下两点在这个颜色的lct是否联通,若联通即为不合法的情况,至于怎么判断,lct模板。

4.对于可以修改颜色的情况,我们就把原来颜色的边cut掉,再link新的颜色就可以了。看下面大佬都是用临接表存边找颜色,我这里教你们一招(懒人专用的奇淫技巧)把bool数组开成char数组这样既可以判断边的存在性,又可以判断边的颜色,比那些临接表方便了许多,还节约了时间。(其实对于一些空间不够的题,可以用short或者char之类的数组来存东西,也许这样就够了)

操作2

没有什么特殊的地方和其它lct题的查询没有什么区别。

总结

这题lct的部分跟其它题目没有区别,直接复制粘贴都可以,只是要想到能开多个lct并且这些lct之间互不影响,实现起来还是非常简单的

代码

#include<bits/stdc++.h>
using namespace std;
const int N=2e5;
int fa[N],ch[N][2],lazy[N],w[N],ans[N],degree[N],n,m,c;
char pd[10001][10001];
int isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
int get(int x){return ch[fa[x]][1]==x;}
void pushup(int x){ans[x]=max(w[x],max(ans[ch[x][0]],ans[ch[x][1]]));}
void pushdown(int x){
    if(!lazy[x])return;
    swap(ch[x][0],ch[x][1]);
    lazy[ch[x][0]]^=1;
    lazy[ch[x][1]]^=1;
    lazy[x]^=1;
}
void rotate(int x){
    int y=fa[x],z=fa[y],k=get(x);
    fa[x]=z;if(!isroot(y))ch[z][ch[z][1]==y]=x;
    ch[y][k]=ch[x][k^1];fa[ch[y][k]]=y;
    ch[x][k^1]=y;fa[y]=x;
    pushup(y);pushup(x);
}
void push(int x){if(!isroot(x))push(fa[x]);pushdown(x);}
void splay(int x){
    push(x);
    while(!isroot(x)){
        int y=fa[x];
        if(!isroot(y))
            if(get(x)==get(y))rotate(y);
            else rotate(x);
        rotate(x);
    }
}
void access(int x){for(int y=0;x;y=x,x=fa[x])splay(x),ch[x][1]=y,pushup(x);}
void makeroot(int x){access(x);splay(x);lazy[x]^=1;}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void link(int x,int y){makeroot(x);fa[x]=y;}
void cut(int x,int y){split(x,y);fa[x]=ch[y][0]=0;pushup(y);}
int getroot(int x){
    access(x);splay(x);
    while(ch[x][0])x=ch[x][0];
    return x;
}
int query(int x,int y){
    if(getroot(x)!=getroot(y))return -1;
    split(x,y);
    return ans[y];
}
void update(int x,int y){
    makeroot(x);
    w[x]=y;
    pushup(x);
}
void work(int x,int y,int z){
    if(pd[x][y]==0){printf("No such edge.\n");return;}
    int u=x+z*n,v=y+z*n,lu=x+pd[x][y]*n,lv=y+pd[x][y]*n;
    if(pd[x][y]==z){printf("Success.\n");return;}
    if(degree[u]==2||degree[v]==2){printf("Error 1.\n");return;}
    if(getroot(u)==getroot(v)){printf("Error 2.\n");return;}
    degree[lu]--;degree[lv]--;
    degree[u]++;degree[v]++;
    cut(lu,lv);
    link(u,v);
    printf("Success.\n");
    pd[x][y]=z;
    pd[y][x]=z;
}
int main(){
    int k;
    cin>>n>>m>>c>>k;
    for(int i=1;i<=n;++i){
        scanf("%d",&w[i]);ans[i]=w[i];
        for(int j=1;j<=c;++j)
            ans[i+j*n]=w[i+j*n]=w[i];
    }
    for(int i=1;i<=m;++i){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        w++;
        int x=u+w*n,y=v+w*n;
        link(x,y);
        degree[x]++;
        degree[y]++;
        pd[u][v]=w;
        pd[v][u]=w;
    }
    while(k--){
        int op;
        scanf("%d",&op);
        if(op==0){
            int x,y;
            scanf("%d%d",&x,&y);
            for(int i=1;i<=c;++i)
                update(x+i*n,y);
        }
        if(op==1){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);z++;
            work(x,y,z);
        }
        if(op==2){
            int x,y,z;
            scanf("%d%d%d",&z,&x,&y);z++;
            printf("%d\n",query(x+z*n,y+z*n));
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/ljq-despair/p/8726814.html

时间: 2024-08-05 03:35:17

[ZJOI2012]网络的相关文章

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 2816: [ZJOI2012]网络(splay)

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

ZJOI2012 网络——LCT相关题目

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

洛谷 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

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

传送门 题解 话说以前还真没见过用LCT只维护一条链的……好像除了树点涂色那题…… 先看一下题目规定的两个性质 对于任意节点连出去的边中,相同颜色的边不超过两条. 图中不存在同色的环,同色的环指相同颜色的边构成的环. 很明显了,同一种颜色肯定是由几条链组成的(虽然我根本没有发现) 然后又要查询边权和维护路径……直接上LCT吧 然后颜色数很少啊……每一个颜色开一个LCT好了 更改权值的话在每一个LCT上splay一下 修改颜色的话在原来的LCT中cut,新的LCT中link 查询路径直接split

P2173 [ZJOI2012]网络

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

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

【醒目】【业界偷懒】【Public】BZOJ题目一句话题解整理

就当是复习一下自己做过的题,顺便提供一个简要题解给大家看. 做题时候实在想不出来看一下一句话题解,可以有一个提示的作用又不至于一下子知道了全部浪费了一道题吧.. 部分题目(如我A过得大部分奶牛题)是别人拿我的账号做的,不提供题解. 可能会漏掉很多做过的题..因为可能点页数不小心点错了什么的 UPD.本来想把那些没写过但是知道题解的也写了..但是写完这些已经累死了QAQ 已AC的题目(数学题均不提供分析过程,公式): 1000:A+B 1001:平面图最小割,转对偶图最短路 1002:矩阵树定理,

LCT总结

类比树剖,树剖是通过静态地把一棵树剖成若干条链然后用一种支持区间操作的数据结构维护(比如线段树.树状数组),而LCT是动态地去处理这个问题. 不少人都知道树剖用线段树维护,而LCT用\(splay\)维护.实际上同一条重链上的所有点才会被放在一棵\(splay\)中,而我们需要同时处理这若干条重链对应的若干棵\(splay\)之间的关系.因为一条重链上的每个点的深度互异,所以\(splay\)以深度\(dep\)为关键字. 我们规定一棵\(splay\)的根的\(fa\)为这条重链链顶节点在原树