20182019-acmicpc-asia-dhaka-regional F .Path Intersection 树链剖分

直接进行树链剖分,每次对路径区间内的所有点值+1,线段树进行维护,然后查询线段树的最大值的个数!!!

查询线段树区间最大值个数,可以先维护区间和,在维护区间最值,如果区间和等于区间最值乘以区间长度,那么直接返回长度!!!

清空的时候,直接减去,不要直接重新建树

#include<bits/stdc++.h>
#define LL long long
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
const int MAXN = 2e5+6;
struct node{
  int l,r;
  int sum,laze;
  int maxx;
}tree[MAXN<<2];
struct edge{
   int Next,to;
}e[MAXN<<1];
int head[MAXN];
int siz[MAXN];
int top[MAXN];
int son[MAXN];
int d[MAXN];
int fa[MAXN];
int id[MAXN];
int sz[MAXN];
int uu[55],vv[55];
int cnt,tot;
void add(int x,int y){
   e[++tot].Next=head[x];
   e[tot].to=y;
   head[x]=tot;
}
void dfs1(int u,int f,int depth){
   d[u]=depth;
   fa[u]=f;
   siz[u]=1;
   for (int i=head[u];i;i=e[i].Next){
     int v=e[i].to;
     if (v==f)
        continue;
     dfs1(v,u,depth+1);
     siz[u]+=siz[v];
     if (siz[v]>siz[son[u]])
        son[u]=v;
   }
}
void dfs2(int u,int t){
    top[u]=t;
    id[u]=++cnt;
    if (!son[u])
        return;
    dfs2(son[u],t);
    for (int i=head[u];i;i=e[i].Next)
    {
        int v=e[i].to;
        if (v!=son[u] && v!=fa[u])
            dfs2(v,v);
    }
}
void push_down(int rt){
    if (tree[rt].laze){
       tree[lson].sum+=(tree[lson].r-tree[lson].l+1)*tree[rt].laze;
       tree[rson].sum+=(tree[rson].r-tree[rson].l+1)*tree[rt].laze;
       tree[lson].maxx+=tree[rt].laze;
       tree[rson].maxx+=tree[rt].laze;
       tree[lson].laze+=tree[rt].laze;
       tree[rson].laze+=tree[rt].laze;
       tree[rt].laze=0;
    }
}
void buildtree(int rt,int l,int r){
    tree[rt].l=l;
    tree[rt].r=r;
    tree[rt].sum=0;
    tree[rt].laze=0;
    tree[rt].maxx=0;
    int mid=(l+r)>>1;
    if (l==r){
        return;
    }
    buildtree(lson,l,mid);
    buildtree(rson,mid+1,r);
}
void update(int rt,int ul,int ur,int w){
   if (ul>ur)return;
   int l=tree[rt].l;
   int r=tree[rt].r;
   if (ul<=l && r<=ur){
     tree[rt].laze+=w;
     tree[rt].maxx+=w;
     tree[rt].sum+=(r-l+1)*w;
     return;
   }
   push_down(rt);
   int mid=(l+r)>>1;
   if (ur<=mid){
     update(lson,ul,ur,w);
   }else if (ul>mid){
     update(rson,ul,ur,w);
   }else {
     update(lson,ul,ur,w);
     update(rson,ul,ur,w);
   }
   tree[rt].maxx=max(tree[lson].maxx,tree[rson].maxx);
   tree[rt].sum=tree[lson].sum+tree[rson].sum;
}
void qRange(int x,int y,int k){
    while(top[x]!=top[y]){
        if (d[top[x]]<d[top[y]])swap(x,y);
        update(1,id[top[x]],id[x],k);
        x=fa[top[x]];
    }
    if (d[x]>d[y])swap(x,y);
    update(1,id[x],id[y],k);
}
int query(int rt,int ql,int qr,int w){
    int l=tree[rt].l;
    int r=tree[rt].r;
    if (tree[rt].sum==w*(r-l+1)){
        return r-l+1;
    }
    if (l==r){
        return 0;
    }
    push_down(rt);
    int mid=(l+r)>>1;
    int ans=0;
    if (tree[lson].maxx==w){
       ans+=query(lson,ql,qr,w);
    }
    if (tree[rson].maxx==w){
        ans+=query(rson,ql,qr,w);
    }
    return ans;
}
int main(){
  int t;
  scanf("%d",&t);
  int n;
  int ca=0;
  while(t--){
     memset(head,0,sizeof(head));
     memset(id,0,sizeof(id));
     memset(top,0,sizeof(top));
     memset(siz,0,sizeof(siz));
     memset(fa,0,sizeof(fa));
     memset(son,0,sizeof(son));
     memset(d,0,sizeof(d));
     scanf("%d",&n);
     cnt=0;
     tot=0;
     int u,v;
     for (int i=1;i<n;i++){
        scanf("%d%d",&u,&v);
        add(u,v);
        add(v,u);
     }
     int r,op,k;
     dfs1(1,0,1);
     dfs2(1,1);
     scanf("%d",&op);
     printf("Case %d:\n",++ca);
     buildtree(1,1,n);
     for (int i=1;i<=op;i++){
       scanf("%d",&k);
       for (int i=1;i<=k;i++){
          scanf("%d%d",&uu[i],&vv[i]);
          qRange(uu[i],vv[i],1);
       }
       int ans=query(1,1,n,k);
       for (int i=1;i<=k;i++){
          qRange(uu[i],vv[i],-1);
       }
       printf("%d\n",ans);
     }
  }
  return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值