• bzoj5392 [Lydsy1806月赛]路径统计


    传送门

    分析

    我们设sum[x]为小于等于x的点现在有多少联通

    于是一个序列合法当且只当sum[R]-sum[L-1]=len且所有点度数不大于2

    我们知道如果对于序列[L,R]满足条件则[L+1,R]一定满足

    如果[L,R]不满足则[L-1,R]一定不满足

    所以我们可以枚举R然后找最靠左的满足度数都小于2的L

    用线段树维护信息查询区间内最大值是R的数的个数就是贡献

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<cctype>
    #include<cmath>
    #include<cstdlib>
    #include<queue>
    #include<ctime>
    #include<vector>
    #include<set>
    #include<map>
    #include<stack>
    using namespace std;
    int n,L,R,num,Max,cnt,col[1200000],d[1200000],sum[1200000],du[260000];
    long long Ans;
    vector<int>high[260000],low[260000];
    inline void build(int le,int ri,int wh){
        sum[wh]=1;
        d[wh]=ri;
        if(le==ri)return;
        int mid=(le+ri)>>1;
        build(le,mid,wh<<1);
        build(mid+1,ri,wh<<1|1);
    }
    inline void pd(int wh){
        if(col[wh]){
          d[wh<<1]+=col[wh];
          col[wh<<1]+=col[wh];
          d[wh<<1|1]+=col[wh];
          col[wh<<1|1]+=col[wh];
          col[wh]=0;
        }
    }
    inline void up(int wh){
        d[wh]=max(d[wh<<1],d[wh<<1|1]);
        sum[wh]=(d[wh<<1]==d[wh]?sum[wh<<1]:0)+(d[wh<<1|1]==d[wh]?sum[wh<<1|1]:0);
    }
    inline void update(int le,int ri,int wh,int x,int y){
        if(le>=x&&ri<=y){
          col[wh]++;
          d[wh]++;
          return;
        }
        pd(wh);
        int mid=(le+ri)>>1;
        if(mid>=x)update(le,mid,wh<<1,x,y);
        if(mid<y)update(mid+1,ri,wh<<1|1,x,y);
        up(wh);
    }
    inline void que(int le,int ri,int wh,int x,int y){
        if(le>=x&&ri<=y){
          if(d[wh]>Max)Max=d[wh],cnt=sum[wh];
            else if(d[wh]==Max)cnt+=sum[wh];
          return;
        }
        pd(wh);
        int mid=(le+ri)>>1;
        if(mid>=x)que(le,mid,wh<<1,x,y);
        if(mid<y)que(mid+1,ri,wh<<1|1,x,y);
        up(wh);
    }
    inline void add(int x){
        for(int i=0;i<low[x].size();i++){
          update(1,n,1,1,low[x][i]);
          if(low[x][i]>=L)num+=((++du[x])==3)+((++du[low[x][i]])==3);
        }
    }
    inline void deal(int x){
        for(int i=0;i<high[x].size();i++){
          if(high[x][i]<=R)num-=((--du[x])==2)+((--du[high[x][i]])==2);
        }
    }
    int main(){
        int i,j,k;
        scanf("%d",&n);
        for(i=1;i<n;i++){
          int x,y;
          scanf("%d%d",&x,&y);
          if(x>y)swap(x,y);
          high[x].push_back(y);
          low[y].push_back(x);
        }
        L=1;
        build(1,n,1);
        for(i=1;i<=n;i++){
          R=i;
          add(i);
          while(num)deal(L),L++;
          Max=0;
          que(1,n,1,L,i);
          if(Max==i)Ans+=1ll*cnt;
        }
        cout<<Ans;
        return 0;
    }
  • 相关阅读:
    进程同步和死锁;事务、悲观锁、乐观锁、表锁、行锁
    快速排序
    oracle索引分类
    数据结构
    MySQL视图
    sql优化的方法
    MySQL索引
    转:关于ROWNUM的使用
    转载:mybatis踩坑之——foreach循环嵌套if判断
    Spring 注意事项
  • 原文地址:https://www.cnblogs.com/yzxverygood/p/10406329.html
Copyright © 2020-2023  润新知