[IOI2018]werewolf狼人——kruskal重構樹+可持久化線段樹

來源:互聯網
上載者:User

標籤:最小產生樹   highlight   font   另一個   因此   stack   最大產生樹   --   new   

題目連結:

IOI2018werewolf

題目中編號都是從0開始,太不舒服了,我們按編號從1開始講QAQ。

題目大意就是詢問每次從一個點開始走只能走編號在[l,n]中的點,在任意點變成狼,之後只能走[0,r]中的點,是否能到達另一個點。

後一部分其實就是找有哪些點只走[0,r]中的點能到達終點,那麼反過來看,就是終點只走[0,r]中的點能到達哪些點。

那麼只要起點能到達的點和終點能到達的點中有交集就有解。

因為起點只能走一些編號較大的點,那麼我們求出原圖的最大產生樹,建出kruskal重構樹,求出重構樹的dfs序,每次詢問在重構樹上倍增找能到達的聯通塊在dfs序上的區間就好了。

相反,從終點走就求出原圖的最小產生樹,然後也按上述方法找。

找到兩段dfs序區間後只要這兩段區間中有相同點就能判有解。

我們將每個點在第一個dfs序中的位置作為橫座標,在第二個dfs序中的位置作為縱座標,剩下的就是一個簡單的二維數點問題了。

等會,上面是不是差點什嗎?原圖沒有邊權啊?

我們以最大產生樹為例,對於一條邊(x,y),兩個點能否通過這條邊互相到達,由這兩個點中較小的點決定,因此求最大產生樹時每條邊邊權就是邊兩端點中較小的那個。最小產生樹邊權就是兩端點中較大的那個。

整體思路就是分別建出原圖最小產生樹和最大產生樹的重構樹,分別求出每個點在兩個重構樹中的dfs序位置,然後可持久化線段樹二維數點。

kruskal重構樹在這裡就不贅述了,如果不是太瞭解可以參考我的另一篇部落格NOI2018歸程,那道題和這道題思想很像。

題面似乎沒說保證整張圖聯通,因此可能是kruskal重構森林。

#include<map>#include<set>#include<stack>#include<queue>#include<cmath>#include<cstdio>#include<vector>#include<bitset>#include<cstring>#include<iostream>#include<algorithm>#define ll long longusing namespace std;struct miku{    int u,v,x,y;}a[400010];int cnt;int n,m,k;int s,t,l,r;int num1,num2;int sum1,sum2;int s1[400010];int s2[400010];int t1[400010];int t2[400010];int q1[400010];int q2[400010];int v1[400010];int v2[400010];int fa1[400010];int fa2[400010];int ls1[400010];int rs1[400010];int ls2[400010];int rs2[400010];int ls[5000010];int rs[5000010];int vis1[400010];int vis2[400010];int sum[5000010];int root[200010];int f1[400010][18];int f2[400010][18];int find1(int x){    if(fa1[x]==x)    {        return x;    }    return fa1[x]=find1(fa1[x]);}int find2(int x){    if(fa2[x]==x)    {        return x;    }    return fa2[x]=find2(fa2[x]);}bool cmp1(miku a,miku b){    return a.x>b.x;}bool cmp2(miku a,miku b){    return a.y<b.y;}void build(int &rt,int l,int r){    rt=++cnt;    if(l==r)    {        return ;    }    int mid=(l+r)>>1;    build(ls[rt],l,mid);    build(rs[rt],mid+1,r);}void updata(int &rt,int pre,int l,int r,int k){    rt=++cnt;    sum[rt]=sum[pre]+1;    if(l==r)    {        return;    }    ls[rt]=ls[pre];    rs[rt]=rs[pre];    int mid=(l+r)>>1;    if(k<=mid)    {        updata(ls[rt],ls[pre],l,mid,k);    }    else    {        updata(rs[rt],rs[pre],mid+1,r,k);    }}int query(int x,int y,int l,int r,int L,int R){    if(L<=l&&r<=R)    {        return sum[y]-sum[x];    }    int mid=(l+r)>>1;    int res=0;    if(L<=mid)    {        res+=query(ls[x],ls[y],l,mid,L,R);    }    if(R>mid)    {        res+=query(rs[x],rs[y],mid+1,r,L,R);    }    return res;}void dfs1(int x){    vis1[x]=1;    s1[x]=sum1;    if(x<=n)    {        q1[++sum1]=x;    }    for(int i=1;i<=17;i++)    {        f1[x][i]=f1[f1[x][i-1]][i-1];    }    if(ls1[x])    {        dfs1(ls1[x]);    }    if(rs1[x])    {        dfs1(rs1[x]);    }    t1[x]=sum1;}void dfs2(int x){    vis2[x]=1;    s2[x]=sum2;    if(x<=n)    {        q2[++sum2]=x;    }    for(int i=1;i<=17;i++)    {        f2[x][i]=f2[f2[x][i-1]][i-1];    }    if(ls2[x])    {        dfs2(ls2[x]);    }    if(rs2[x])    {        dfs2(rs2[x]);    }    t2[x]=sum2;}int ST1(int x,int val){    for(int i=17;i>=0;i--)    {        if(v1[f1[x][i]]>=val&&f1[x][i]!=0)        {            x=f1[x][i];        }    }    return x;}int ST2(int x,int val){    for(int i=17;i>=0;i--)    {        if(v2[f2[x][i]]<=val&&f2[x][i]!=0)        {            x=f2[x][i];        }    }    return x;}int main(){    scanf("%d%d%d",&n,&m,&k);    for(int i=1;i<=m;i++)    {        scanf("%d%d",&a[i].u,&a[i].v);        a[i].u++;        a[i].v++;        a[i].x=min(a[i].u,a[i].v);        a[i].y=max(a[i].u,a[i].v);    }    for(int i=1;i<2*n;i++)    {        fa1[i]=i;        fa2[i]=i;    }    num1=num2=n;    sort(a+1,a+1+m,cmp1);    for(int i=1;i<=m;i++)    {        int fx=find1(a[i].u);        int fy=find1(a[i].v);        if(fx!=fy)        {            num1++;            v1[num1]=a[i].x;            ls1[num1]=fx;            rs1[num1]=fy;            f1[fx][0]=num1;            f1[fy][0]=num1;            fa1[fx]=num1;            fa1[fy]=num1;            if(num1==2*n-1)            {                break;            }        }    }    for(int i=1;i<=n;i++)    {        if(!vis1[i])        {            dfs1(find1(i));        }    }    sort(a+1,a+1+m,cmp2);    for(int i=1;i<=m;i++)    {        int fx=find2(a[i].u);        int fy=find2(a[i].v);        if(fx!=fy)        {            num2++;            v2[num2]=a[i].y;            ls2[num2]=fx;            rs2[num2]=fy;            f2[fx][0]=num2;            f2[fy][0]=num2;            fa2[fx]=num2;            fa2[fy]=num2;            if(num2==2*n-1)            {                break;            }        }    }    for(int i=1;i<=n;i++)    {        if(!vis2[i])        {            dfs2(find2(i));        }    }    build(root[0],1,n);    for(int i=1;i<=n;i++)    {        updata(root[i],root[i-1],1,n,s2[q1[i]]+1);    }    while(k--)    {        scanf("%d%d%d%d",&s,&t,&l,&r);        s++;        t++;        l++;        r++;        s=ST1(s,l);        t=ST2(t,r);        int ans=query(root[s1[s]],root[t1[s]],1,n,s2[t]+1,t2[t]);        if(ans==0)        {            printf("0\n");        }        else        {            printf("1\n");        }    }}

[IOI2018]werewolf狼人——kruskal重構樹+可持久化線段樹

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.