jzoj6276. 【noip提高组模拟1】树

Time Limits: 1000 ms
Memory Limits: 524288 KB
Description

有一棵n个节点的无根树,给出其中的m对点对<x,y>。问有多少条树上的简单路径<u,v>满足该路径上不存在任何一对给出的点对<x,y>。
这里我们认为路径<u,v>和<v,u>是相同的。并且对于题目中给出的点对<x,y>满足x!=y,对于你要计数的路径<u,v>满足u!=v(即单点不算答案)。

Input

第一行两个正整数n,m。
接下来n-1行每行两个正整数u,v描述树上的一条边。
接下来m行每行两个正整数x,y描述一对给出的点对。
(注意,这里我们不保证同样的点对<x,y>不会重复出现)

Output

一行一个整数,表示满足要求的树上简单路径的条数。

Sample Input

8 3
1 2
1 3
4 8
2 4
2 5
3 6
3 7
2 3
4 8
6 7

Sample Output

11

Data Constraint

在这里插入图片描述

Hint

满足条件的路径为<1,2>,<1,3>,<1,4>,<1,5>,<1,6>,<1,7>,<2,4>,<2,5>,< 3,6>,< 3,7>,<4,5>。

赛时

一看到这么多的√,心想——一定可以水到巨多的分数。
看到m=1,不是送的吗?直接拿总答案减去不合法的即可。
看到菊花图,不是送的吗?如果不合法的限制一个是叶子,一个是根,则把叶子删掉。
剩下的-1即可。
看到链的情况,发现不会。
然后又发现n和m那么小,于是稳拿70.
最后发现,我™把调试程序交上去了!!!(调试输出的东西没删)
然后还没发现到限制重复。
10分妙啊♂

题解

部分分上面说过了,除了链的情况。
我们发现,对于链,直观的想法——设限制为x,y,y是x的祖宗。
那么y的祖先与x的儿子两两匹配都是不行的(显然)。
那么我们弄出一个二维平面,x轴表示从第i个点出发,y轴表示抵达第j个点。
这样就变成了在二维平面内有很多矩形,这些矩形内的点不能选。
这玩意不是扫描线吗?

即可解决,拿到90分的好成绩。

等等,既然我们想到这里了,100分不就很显然了吗?
我们对于数弄出dfn序,那么我们可以很轻松地处理出每个点对应的子树。
在二维平面内搞搞即可。
但是!如果y是x祖宗这类情况怎么办?
很简单,求出一个y到x简单路径中距离y最近的点z。
然后由于是dfn序,那么对于y以外的点就是除了z子树范围的其他点。
分成两个区间即可。

标程
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
using namespace std;

struct node
{
    int a,b,x,y;
};
struct node1
{
    int l,r,x,k;
};
struct node2
{
    int a,lazy;
};

int q,x,y,tot,lx,ly,num,op,p,now;
long long ans,size[100011],n;
int tov[200011],next[200011],last[200011],fa[100011],qx[100001],qy[100001],dep[100011],rd[100011],ii[100011],st[100001],en[100001],f[100001][18];
bool bz[201],kk[100001];
node1 lis[800001];
node gin[800001];
node2 tree[800001];

void joinit(int p)
{
    op++;lis[op].l=gin[p].x;lis[op].r=gin[p].y;lis[op].x=gin[p].a;lis[op].k=1;
    op++;lis[op].l=gin[p].x;lis[op].r=gin[p].y;lis[op].x=gin[p].b+1;lis[op].k=-1;
    op++;lis[op].l=gin[p].a;lis[op].r=gin[p].b;lis[op].x=gin[p].x;lis[op].k=1;
    op++;lis[op].l=gin[p].a;lis[op].r=gin[p].b;lis[op].x=gin[p].y+1;lis[op].k=-1;
}

void make_tree(int k,int l,int r)
{
    tree[k].a=r-l+1;
    tree[k].lazy=0;
    if (l!=r)
    {
        int mid=(l+r)/2;
        make_tree(k*2,l,mid);
        make_tree(k*2+1,mid+1,r);
    }
}

void update(int x,int l,int r)
{
    if (tree[x].lazy==0)
    {
        tree[x].a=tree[x*2].a+tree[x*2+1].a;
        if (l==r) tree[x].a=1;
    }
    else
    {
        tree[x].a=0;
    }
}

void change(int x,int l,int r,int st,int en,int gb)
{
    if (l<=en && r>=st)
    {
        if (l>=st && r<=en)
        {
            tree[x].lazy=tree[x].lazy+=gb;
            update(x,l,r);
        }
        else
        {
            int m=(l+r)/2;
            change(x*2,l,m,st,en,gb);
            change(x*2+1,m+1,r,st,en,gb);
            update(x,l,r);
        }
    }
    else return;
}

void insert(int x,int y)
{
    tot++;
    tov[tot]=y;
    next[tot]=last[x];
    last[x]=tot;
}

void dfs(int x)
{
    num++;
    st[x]=num;
    size[x]=1;
    f[x][0]=fa[x];
    for (ii[x]=0;ii[x]<=17;ii[x]++)
    {
        if (f[x][ii[x]]!=0 && f[f[x][ii[x]]][ii[x]]!=0)
        {
            f[x][ii[x]+1]=f[f[x][ii[x]]][ii[x]];
        }
        else break;
    }
    
    ii[x]=last[x];
    while (ii[x]>0)
    {
        if (tov[ii[x]]!=fa[x])
        {
            fa[tov[ii[x]]]=x;
            dep[tov[ii[x]]]=dep[x]+1;
            dfs(tov[ii[x]]);
            size[x]+=size[tov[ii[x]]];
        }
        ii[x]=next[ii[x]];
    } 
    en[x]=num;
}

void qsort(int l,int r)
{
    int i=l;int j=r;
    int m=qx[(i+j)/2];
    int m1=qy[(i+j)/2];
    while (i<=j)
    {
        while ((qx[i]<m) || (qx[i]==m && qy[i]>m1)) i++;
        while ((qx[j]>m) || (qx[j]==m && qy[j]<m1)) j--;
        if (i<=j)
        {
            swap(qx[i],qx[j]);
            swap(qy[i],qy[j]);
            i++;j--;
        }
    }
    if (l<j) qsort(l,j);
    if (r>i) qsort(i,r); 
}

void qsort1(int l,int r)
{
    int i=l;int j=r;
    int m=lis[(i+j)/2].x;
    while (i<=j)
    {
        while (lis[i].x<m) i++;
        while (lis[j].x>m) j--;
        if (i<=j)
        {
            swap(lis[i],lis[j]);
            i++;j--;
        }
    }
    if (l<j) qsort1(l,j);
    if (r>i) qsort1(i,r); 
}

int get_lca(int x,int y)
{
    if (dep[x]<dep[y])
    {
        swap(x,y);  
    }
    int i=17;
    while (i>=0)
    {
        if (dep[f[x][i]]>dep[y])
        {
            x=f[x][i];
        }
        i--;
    }
    if (x==y) return y;
    else
    {
        for (int i=17;i>=0;i--);
        if (f[x][i]!=f[y][i])
        {
            x=f[x][i];
            y=f[y][i];
        }
        return f[x][0];
    }
}

int main()
{
    freopen("tree.in","r",stdin);
    freopen("tree.out","w",stdout);
    scanf("%lld%d",&n,&q);
    for (int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        insert(x,y);
        insert(y,x);
        rd[x]++;rd[y]++;
    }
    dfs(1);
    for (int i=1;i<=q;i++)
    {
        scanf("%d%d",&qx[i],&qy[i]);
    }
    {
        int p=0;
        for (int i=1;i<=q;i++)
        {
            if (qx[i]!=qx[i-1] || qy[i]!=qy[i-1])
            {
                if (dep[qx[i]]<=dep[qy[i]]) swap(qx[i],qy[i]);
                int lca=get_lca(qx[i],qy[i]);
                if (qx[i]!=lca && qy[i]!=lca)
                {
                    p++;gin[p].a=st[qx[i]];gin[p].x=st[qy[i]];gin[p].b=en[qx[i]];gin[p].y=en[qy[i]];
//                  printf("%d %d %d %d\n",gin[p].a,gin[p].b,gin[p].x,gin[p].y);
                    joinit(p);
                }
                else
                {
                    int k=qx[i];
                    int j=17;
                    while (j>=0)
                    {
                        if (dep[f[k][j]]>dep[qy[i]]) k=f[k][j];
                        j--;
                    }
                    p++;gin[p].a=st[qx[i]];gin[p].x=1;gin[p].b=en[qx[i]];gin[p].y=st[k]-1;
//                  printf("%d %d %d %d\n",gin[p].a,gin[p].b,gin[p].x,gin[p].y);
                    joinit(p);
                    //if (en[k]!=n)
                    {
                        p++;gin[p].a=st[qx[i]];gin[p].x=en[k]+1;gin[p].b=en[qx[i]];gin[p].y=n;
//                      printf("%d %d %d %d\n",gin[p].a,gin[p].b,gin[p].x,gin[p].y);
                        joinit(p);
                    }
                }
            }
        }
    }
    make_tree(1,1,n);
    qsort1(1,op);
    ans=0;
    now=1;
    for (int i=1;i<=n;i++)
    {
        while (now<=op && lis[now].x==i)
        {
            change(1,1,n,lis[now].l,lis[now].r,lis[now].k);
            now++;
        }
        ans+=tree[1].a;
    }
    ans-=n;
    printf("%lld\n",ans/2);
}

转载于:https://www.cnblogs.com/RainbowCrown/p/11324176.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值