12
18
2015
0

【JSOI2015】最小生成树

难以描述的痛苦。。

我们先预处理出边权大于等于x的边形成的最小生成树或最小生成森林,这些边用主席树存。

那么,如何维护呢,我们从边权从大到小枚举,每次在原来基础上新加一条边后,如果产生了环,就把环中最大的边删去。这样就可以用主席树来维护。

然后对于每个询问l,r,我们只要在root[l]这棵主席树上求边权小于等于r的边权和,这很容易吧。。

这样本题就结束了。orz Gold_7 first blood!!!

代码:

 

#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,q,A,p,d,edgenum,cnt,Max,l,r,ans;
int vet[2000010],next[2000010],head[2000010],a[2000010],f[2000010],flag[2000010],root[2000010],e[2000010],dis[2000010];
struct tree{int l,r,sum;}tr[20000010];
struct node{int x,y,z;}ed[2000010];
bool cmp(const node a,const node b){return a.z<b.z;}
int getfather(int x){if (x!=f[x]) f[x]=getfather(f[x]);return f[x];}
void change(int &p,int l,int r,int x,int val)
{
    tr[++cnt]=tr[p];p=cnt;tr[p].sum+=val;
    if (l==r) return;
    int mid=(l+r)>>1;
    if (x<=mid) change(tr[p].l,l,mid,x,val);else change(tr[p].r,mid+1,r,x,val);
}
int ask(int p,int l,int r,int x)
{
    if (r<=x) return tr[p].sum;
    int mid=(l+r)>>1;
    if (x<=mid) return ask(tr[p].l,l,mid,x);else return ask(tr[p].l,l,mid,x)+ask(tr[p].r,mid+1,r,x);
}
void add(int u,int v,int w)
{
    edgenum++;
    vet[edgenum]=v;
    next[edgenum]=head[u];
    head[u]=edgenum;
    dis[edgenum]=w;
}
int dfs(int u,int t,int fa)
{
    if (u==t&&fa!=-1) return 1;
    for (int e=head[u];e;e=next[e])
    {
        int v=vet[e];
        if ((e+1)/2==fa) continue;
        if (dfs(v,t,(e+1)/2)){flag[(e+1)/2]=1;return 1;}
    }
    return 0;
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++)
        scanf("%d%d%d",&ed[i].x,&ed[i].y,&ed[i].z);
    sort(ed+1,ed+m+1,cmp);
    for (int i=1;i<=n;i++) f[i]=i;
    for (int i=1;i<=m;i++) e[i]=ed[i].z;
    for (int i=m;i>=1;i--)
    {
        root[i]=root[i+1];
        if (getfather(ed[i].x)!=getfather(ed[i].y))
        {
            f[getfather(ed[i].x)]=getfather(ed[i].y);
            a[++a[0]]=i;
            change(root[i],1,m,i,ed[i].z);
        }else
        {
            Max=-1;
            edgenum=0;
            for (int j=1;j<=n;j++) head[j]=0;
            for (int j=1;j<=a[0];j++)
            {
                add(ed[a[j]].x,ed[a[j]].y,ed[a[j]].z);
                add(ed[a[j]].y,ed[a[j]].x,ed[a[j]].z);
            }
            add(ed[i].x,ed[i].y,ed[i].z);
            add(ed[i].y,ed[i].x,ed[i].z);
            for (int j=1;j<=edgenum/2;j++)
                flag[j]=0;
            dfs(ed[i].x,ed[i].x,-1);
            for (int j=1;j<=edgenum/2;j++)
            if (flag[j]) Max=max(Max,dis[j*2]);
            for (int j=1;j<=a[0];j++)
                if (ed[a[j]].z==Max&&flag[j])
                {
                    change(root[i],1,m,a[j],-ed[a[j]].z);
                    for (int k=j;k<a[0];k++) a[k]=a[k+1];
                    a[0]--;
                    break;
                }
            a[++a[0]]=i;
            change(root[i],1,m,i,ed[i].z);
        }
    }
    scanf("%d%d",&q,&A);
    while (q--)
    {
        scanf("%d%d",&p,&d);
        l=ans*A+p;r=l+d;
        l=lower_bound(e+1,e+m+1,l)-e;
        r=upper_bound(e+1,e+m+1,r)-e-1;
        ans=ask(root[l],1,m,r);
        printf("%d\n",ans);
    }
}
Category: 主席树 | Tags: | Read Count: 239

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com