码迷,mamicode.com
首页 > 其他好文 > 详细

染色(dye)

时间:2018-03-14 22:09:18      阅读:177      评论:0      收藏:0      [点我收藏+]

标签:typename   output   gpo   des   计算   连通图   microsoft   one   play   

染色(dye)

Description

Serene 和 Achen 在玩染色游戏。Serene 和 Achen 站在一个 n 个点 m 条边的无向连通图中,在第 i 次玩染色游戏时,Serene 在 a_i,Achen 在 b_i,并且所有节点都变为白色,在这次游戏中,Serene 和 Achen 会走过一些边,并且把路途中经过的所有点染成黑色,她们一共需要把 k_i 个点染成黑色(一个点如 果被染多次只计算一次)。

但是 Serene 和 Achen 不想太累,她们的劳累值是她们俩所经过的所有的边的最 大编号。Serene 想知道,每次玩染色游戏时 Serene 和 Achen 的最小的劳累值。

Input

一行两个整数 n,m

接下来 m 行每行两个数 x_i,y_i 表示编号为 i 的边所连接的两个点

接下来一行一个数 q,表示 Serene 和 Achen 做游戏的次数

接下来 q 行每行两个数 a_i,b_i,k_i 表示 Serene 和 Achen 的初始位置和需要染成黑色的点数

Output

q 行,对于每次游戏输出最小劳累值。

Sample Input

5 6

2 3

4 5

1 2

1 3

1 4

1 5

6

2 4 3

2 4 4

2 4 5

1 3 3

1 3 4

1 3 5

Sample Output

1

2

3

1

5

5

Hint

对于 20%的数据,n,m,q<=500

对于 60%的数据,n,m,q<=50000

对于 100%的数据,n,m,q<=200000

原题

整体二分。

二分的一个答案显然可以用并查集维护。

若是每次暴力从头建并查集肯定会死亡TLE。

于是用按秩合并的并查集,每次二分之后先往又区间走,往右走之后操作是往并查集里加。

走完不得不往左走时,把之前操作的后一半撤销。为了撤销强行开了个栈存操作。

然后奥妙地跑得比std快。

正解是整体二分时不按dfs序做而是按bfs序做。

技术分享图片
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<queue>
#include<cmath>
const int N=400007;
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(int i=(a);i>=(b);i--)
typedef long long LL;
using namespace std;
int n,m,q,fa[N],sz[N],ans[N];

template<typename T>void read(T &x)  {
    char ch=getchar(); x=0; T f=1;
    while(ch!=-&&(ch<0||ch>9)) ch=getchar();
    if(ch==-) f=-1,ch=getchar();
    for(;ch>=0&&ch<=9;ch=getchar()) x=x*10+ch-0; x*=f;
}

struct edge {
    int u,v,w;
}e[N];

struct node {
    int x,y,k,id;
}qs[N],tp[N];

int find(int x) { return x==fa[x]?x:find(fa[x]); }

struct op {
    int x,fa,id;
    op(){}
    op(int x,int fa,int id):x(x),fa(fa),id(id){}
}sta[N*18];
int top;
void solve(int l,int r,int ql,int qr,int f) {
    if(l>r||ql>qr) return ;
    if(l==r) {
        For(i,ql,qr) ans[qs[i].id]=l;
        return;
    }
    int mid=((l+r)>>1);
    int ll=ql-1,rr=qr+1;
    if(f) {
        For(i,l,mid) {
            int x=find(e[i].u),y=find(e[i].v);
            if(x!=y) {
                if(sz[x]<=sz[y]) {
                    fa[x]=y,sz[y]+=sz[x];
                    sta[++top]=op(x,y,i);
                }
                else  {
                    fa[y]=x,sz[x]+=sz[y];
                    sta[++top]=op(y,x,i);
                }
            }
        }
    }
    For(i,ql,qr) {
        int x=find(qs[i].x),y=find(qs[i].y);
        if((x==y&&sz[x]>=qs[i].k)||(x!=y&&sz[x]+sz[y]>=qs[i].k)) tp[++ll]=qs[i];
        else tp[--rr]=qs[i];
    }
    For(i,ql,qr) qs[i]=tp[i];
    solve(mid+1,r,rr,qr,1);
    Rep(i,top,1) {
        if(sta[i].id<=((l+mid)>>1)) break;
        int x=sta[i].x,f=sta[i].fa;
        fa[x]=x; sz[f]-=sz[x]; top--;
    }
    solve(l,mid,ql,ll,0);
}

#define DEBUG
int main() {
#ifdef DEBUG
    freopen("dye.in","r",stdin);
    freopen("dye.out","w",stdout);
#endif
    read(n); read(m);
    For(i,1,m) {
        read(e[i].u); read(e[i].v); 
        e[i].w=i;
    }
    read(q);
    For(i,1,q) {
        read(qs[i].x); read(qs[i].y);
        read(qs[i].k); qs[i].id=i;
    }
    For(i,1,n) fa[i]=i,sz[i]=1;
    solve(1,m,1,q,1);
    For(i,1,q) printf("%d\n",ans[i]);
    return 0;
}
/*
5 6
2 3
4 5
1 2
1 3
1 4
1 5
6
2 4 3
2 4 4
2 4 5
1 3 3
1 3 4
1 3 5
*/
View Code

 

 

 

染色(dye)

标签:typename   output   gpo   des   计算   连通图   microsoft   one   play   

原文地址:https://www.cnblogs.com/Achenchen/p/8570152.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!