• gym 102040F 水树剖+odt维护


    题意:

    一棵树,多次询问,每次询问k条路径上的相交点个数,k只有几十个

    题解:

    显然,对于每个路径进行树链+1,答案就是为k的点的个数,由于询问的特殊性,我们直接用odt维护就行

    最后速度还好

    #include <bits/stdc++.h>
    #define endl '
    '
    #define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
    #define rep(ii,a,b) for(int ii=a;ii<=b;++ii)
    #define forn(ii,now) for(int ii=head[now];ii;ii=e[ii].next)
    using namespace std;
    const int maxn=1e6+10,maxm=2e6+10;
    int casn,n,m,k;
    class odtree{public:
      struct segnode{
        int l,r;mutable int val;
        bool operator<(const segnode &b)const {return l<b.l;}
      };
      set<segnode> nd;
      void init(int n=maxn-5){nd.clear();nd.insert({1,n,0});}
      auto split(int pos){
        auto it=nd.lower_bound({pos,pos,0});
        if(it!=nd.end()&&it->l==pos) return it;
        it--;
        int l=it->l,r=it->r,val=it->val;
        nd.erase(it);nd.insert({l,pos-1,val});
        return nd.insert({pos,r,val}).fi;
      }
      void update(int l,int r,int val){
        auto itr=split(r+1),itl=split(l);
        for(auto it=itl;it!=nd.end()&&(it->l)<=r;++it){
          ++(it->val);
        }
      }
      int query(int l,int r,int k){
        auto itr=split(r+1),itl=split(l);
        int sum=0;
        for(auto it=itl;it!=nd.end()&&(it->l)<=r;++it){
          if((it->val)==k) sum+=(it->r)-(it->l)+1;
        }
        return sum;
      }
    }tree;
    class chain{public:
    	struct node{int to,next;}e[maxn<<1];
    	int head[maxn],nume,mp[maxn];
    	inline void add(int a,int b){
    		e[++nume]={b,head[a]};
    		head[a]=nume;
    	}
    	int ltop[maxn],fa[maxn],deep[maxn];
    	int sz[maxn],remp[maxn];
    	int son[maxn],cnt;
    	void init(int n){rep(i,1,n) head[i]=0;cnt=0,nume=1;}
      void dfs1(int now=1,int pre=1,int d=0){
    		deep[now]=d,fa[now]=pre,sz[now]=1,son[now]=0;
    		forn(i,now){
    			int to=e[i].to;
    			if(to!=pre) {
    				dfs1(to,now,d+1);
    				sz[now]+=sz[to];
    				if(sz[to]>sz[son[now]]) son[now]=to;
    			}
    		}
      }
      void dfs2(int now=1,int pre=1,int sp=1){
        ltop[now]=sp;mp[now]=++cnt;remp[cnt]=now;
          if(son[now])  dfs2(son[now],now,sp);
          forn(i,now){
            int to=e[i].to;
            if(to!=son[now]&&to!=pre) dfs2(to,now,to);
          }
      }
      void update(int a,int b,int val){
        while(ltop[a]!=ltop[b]){
            if(deep[ltop[a]]<deep[ltop[b]])swap(a,b);
            tree.update(mp[ltop[a]],mp[a],val);
            a=fa[ltop[a]];
        }
          if(deep[a]>deep[b])swap(a,b);
          tree.update(mp[a],mp[b],val);
      }
      int query(int a,int b,int k){
        int sum=0;
        while(ltop[a]!=ltop[b]){
            if(deep[ltop[a]]<deep[ltop[b]])swap(a,b);
            sum+=tree.query(mp[ltop[a]],mp[a],k);
            a=fa[ltop[a]];
        }
          if(deep[a]>deep[b])swap(a,b);
          sum+=tree.query(mp[a],mp[b],k);
          return sum;
      }
      int lca(int x,int y){
        for(;ltop[x]!=ltop[y];deep[ltop[x]]>deep[ltop[y]]?x=fa[ltop[x]]:y=fa[ltop[y]]);
        return deep[x]<deep[y]?x:y;
      }
      void div(){dfs1();dfs2();}
    }g;
    
    int main(){
      IO;
      cin>>casn;
      rep($,1,casn){
        cout<<"Case "<<$<<":"<<endl;
        cin>>n;g.init(n);
        rep(i,2,n){
          int a,b;cin>>a>>b;
          g.add(a,b);g.add(b,a);
        }
        g.div();cin>>m;
        while(m--){
          cin>>k;
          int a,b;
          tree.init(n);
          rep(_,1,k){
            cin>>a>>b;
            g.update(a,b,1);
          }
          cout<<g.query(a,b,k)<<endl;
        }
      }
    }
    
  • 相关阅读:
    VIM 配色方案,先保存一下
    ncurses库的介绍与安装
    win7 设置双屏壁纸
    3. Vim入门教程
    2. Vim 概念扫盲
    把Debian 设置中文环境
    静态代码块和构造代码块的区别
    jsp详解(3个指令、6个动作、9个内置对象、11个隐式对象)
    JVM虚拟机详解
    Java 的内置对象
  • 原文地址:https://www.cnblogs.com/nervendnig/p/10868745.html
Copyright © 2020-2023  润新知