BZOJ4399 魔法少女LJJ(线段树合并)

  注意到只有增加点/合并的操作。这些操作都可以用线段树完成,于是线段树合并一发就好了。注意乘积大小直接比较肯定会炸,取个对数即可。数据中存在重边。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 400010
#define inf 1000000000
int m,tot,fa[N],root[N],cnt;
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
struct data{int l,r,s;double v;bool f;
}tree[N*16];
void up(int k)
{
    tree[k].s=tree[tree[k].l].s+tree[tree[k].r].s;
    tree[k].v=tree[tree[k].l].v+tree[tree[k].r].v;
}
void down(int k)
{
    tree[tree[k].l].f=tree[tree[k].r].f=1;
    tree[tree[k].l].s=tree[tree[k].r].s=0;
    tree[tree[k].l].v=tree[tree[k].r].v=0;
    tree[k].f=0;
}
void ins(int &k,int l,int r,int x,int s,double y)
{
    if (!k) k=++cnt;
    tree[k].v+=y;tree[k].s+=s;
    if (l==r) return;
    if (tree[k].f) down(k);
    int mid=l+r>>1;
    if (x<=mid) ins(tree[k].l,l,mid,x,s,y);
    else ins(tree[k].r,mid+1,r,x,s,y);
}
int merge(int x,int y,int l,int r)
{
    if (!x||!y) return x|y;
    tree[x].s+=tree[y].s,tree[x].v+=tree[y].v;
    if (l<r)
    {
        if (tree[x].f) down(x);if (tree[y].f) down(y);
        int mid=l+r>>1;
        tree[x].l=merge(tree[x].l,tree[y].l,l,mid);
        tree[x].r=merge(tree[x].r,tree[y].r,mid+1,r);
    }
    return x;
}
int modify(int k,int l,int r,int x,int y)
{
    if (x>y||!k) return 0;
    if (l==x&&r==y)
    {
        int p=tree[k].s;
        tree[k].s=0,tree[k].v=0,tree[k].f=1;
        return p;
    }
    if (tree[k].f) down(k);
    int mid=l+r>>1,ans;
    if (y<=mid) ans=modify(tree[k].l,l,mid,x,y);
    else if (x>mid) ans=modify(tree[k].r,mid+1,r,x,y);
    else ans=modify(tree[k].l,l,mid,x,mid)+modify(tree[k].r,mid+1,r,mid+1,y);
    up(k);
    return ans;
}
int query(int k,int l,int r,int x)
{
    if (l==r) return l;
    if (tree[k].f) down(k);
    int mid=l+r>>1;
    if (tree[tree[k].l].s>=x) return query(tree[k].l,l,mid,x);
    else return query(tree[k].r,mid+1,r,x-tree[tree[k].l].s);
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj4399.in","r",stdin);
    freopen("bzoj4399.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    m=read();
    while (m--)
    {
        int op=read();
        switch(op)
        {
            case 1:
            {
                fa[++tot]=tot;int x=read();
                ins(root[tot],1,inf,x,1,log(x));
                break;
            }
            case 2:
            {
                int x=find(read()),y=find(read());
                if (x!=y) root[x]=merge(root[x],root[y],1,inf);
                fa[y]=x;
                break;
            }
            case 3:
            {
                int p=find(read()),x=read();
                int s=modify(root[p],1,inf,1,x-1);
                ins(root[p],1,inf,x,s,s*log(x));
                break;
            }
            case 4:
            {
                int p=find(read()),x=read();
                int s=modify(root[p],1,inf,x+1,inf);
                ins(root[p],1,inf,x,s,s*log(x));
                break;
            }
            case 5:
            { 
                int p=find(read()),x=read();
                printf("%d\n",query(root[p],1,inf,x));
                break;
            }
            case 6:
            {
                int x=find(read()),y=find(read());
                printf("%d\n",tree[root[x]].v>tree[root[y]].v);
                break;
            }
            case 7:
            {
                int x=find(read());
                printf("%d\n",tree[root[x]].s);
                break;
            }
        }
    }
    return 0;
}

 

posted @ 2018-10-29 09:59  Gloid  阅读(202)  评论(0编辑  收藏  举报