zoukankan      html  css  js  c++  java
  • A

    Description

      
    img
    img
      
      
      

    Solution

      
      ​ 我连暴力都不会打,我真的是个弱鸡。
      
    ​   发现很难合并两条合法的路径,然而我的思维限死了,一直在想怎么点分,判断路径是否合法,连暴力都打不出来。
      
    ​   参与运算的是顶点标号,这意味着形如(a_i ightarrow ka_i)危险路径只有(O(n;log;n))对。不合法的路径,必定经过至少一条危险路径。这玩意其实很好算,于是答案就是总路径数减去不合法的路径数。
      
    ​   记(dfn[a])表示(a)的dfs入序,(end[a])表示(a)的dfs出序。
      
    ​   把任意一条路径(a ightarrow b)看作二维平面上的一个点((dfn[a],dfn[b])),现在我们要通过高效的方式将不合法的点标记出来。
      
    ​   对于一条危险路径(u ightarrow v),考虑任意一条路径(a ightarrow b)(dfn[u]<dfn[v])(dfn[a]<dfn[b])),记(g)(u)(v)的路径上第一个碰到的不是(u)的点。
      
    ​   若(u)(v)的祖先,则不合法的路径要么满足(dfn[a]in[1,dfn[g]))(dfn[b]in[dfn[v],end[v]]),要么满足(dfn[a]in[dfn[v],end[v]])(dfn[b]in(end[g],n])。将对应的两个矩形的所有元素标记为不合法。
      
    ​   否则更能简单,不合法的路径一定满足(dfn[a]in[dfn[u],end[u]])(dfn[b]in[dfn[v],end[v]])
      
    ​   做个矩形求并,用全面积减去矩形总面积就是合法方案数了。(细节除2、线段树的一个叶子代表是一条网格边之类的注意一下就可以了)
      
      
      

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    const int N=100005;
    int n;
    int h[N],tot,pre[N][18],dep[N];
    int dfntm,dfn[N][2];
    struct Edge{int v,next;}e[N*2];
    struct Data{
    	int y,l,r,d;
    	Data(){}
    	Data(int _y,int _l,int _r,int _d){y=_y;l=_l;r=_r;d=_d;}
    }a[N*17*2];
    int acnt;
    inline void swap(int &x,int &y){x^=y^=x^=y;}
    inline int getInt(){
    	int x=0,f=1; char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while('0'<=c&&c<='9'){x=x*10+c-'0';c=getchar();}
    	return x*f;
    }
    inline void addEdge(int u,int v){
    	e[++tot].v=v; e[tot].next=h[u]; h[u]=tot;
    	e[++tot].v=u; e[tot].next=h[v]; h[v]=tot;
    }
    void predfs(int u,int fa){
    	pre[u][0]=fa;
    	dep[u]=dep[fa]+1;
    	dfn[u][0]=++dfntm;
    	for(int i=1;i<=17;i++) pre[u][i]=pre[pre[u][i-1]][i-1];
    	for(int i=h[u],v;i;i=e[i].next)
    		if((v=e[i].v)!=fa)
    			predfs(v,u);
    	dfn[u][1]=dfntm;
    }
    inline int jump(int u,int step){
    	for(int i=17;i>=0;i--)
    		if((1<<i)<=step)
    			u=pre[u][i],step-=(1<<i);
    	return u;
    }
    void createRect(int u,int v){
    	if(dfn[u][0]>dfn[v][0]) swap(u,v);
    	int g=jump(v,dep[v]-dep[u]-1);
    	if(pre[g][0]==u){//u是v的祖先
    		if(dfn[g][0]-1>=1){
    			a[++acnt]=Data(dfn[v][0],1,dfn[g][0]-1,1);
    			a[++acnt]=Data(dfn[v][1]+1,1,dfn[g][0]-1,-1);
    		}
    		if(dfn[g][1]+1<=n){
    			a[++acnt]=Data(dfn[g][1]+1,dfn[v][0],dfn[v][1],1);
    			a[++acnt]=Data(n+1,dfn[v][0],dfn[v][1],-1);
    		}
    	}
    	else{//u和v分列两侧
    		a[++acnt]=Data(dfn[v][0],dfn[u][0],dfn[u][1],1);
    		a[++acnt]=Data(dfn[v][1]+1,dfn[u][0],dfn[u][1],-1);	
    	}
    }
    namespace SEG{
    	int rt,sz,ch[N*2][2],cnt[N*2],sum[N*2];
    	void build(int &u,int l,int r){
    		u=++sz;
    		if(l==r) return;
    		int mid=(l+r)>>1;
    		build(ch[u][0],l,mid);
    		build(ch[u][1],mid+1,r);
    	}
    	inline void pushup(int u,int l,int r){
    		sum[u]=cnt[u]?r-l+1:sum[ch[u][0]]+sum[ch[u][1]];
    	}
    	void modify(int u,int l,int r,int L,int R,int x){
    		if(L<=l&&r<=R){
    			cnt[u]+=x;
    			pushup(u,l,r);
    			return;
    		}
    		int mid=(l+r)>>1;
    		if(R<=mid) modify(ch[u][0],l,mid,L,R,x);
    		else if(mid<L) modify(ch[u][1],mid+1,r,L,R,x);
    		else{
    			modify(ch[u][0],l,mid,L,mid,x);
    			modify(ch[u][1],mid+1,r,mid+1,R,x);
    		}
    		pushup(u,l,r);
    	}
    	int query(){return sum[1];}
    }
    bool cmp(const Data &a,const Data &b){
    	if(a.y!=b.y) return a.y<b.y;
    	if(a.l!=b.l) return a.l<b.l;
    	return a.r<b.r;
    }
    int main(){
    	n=getInt();
    	for(int i=1;i<n;i++){
    		int u=getInt(),v=getInt();
    		addEdge(u,v);
    	}
    	predfs(1,0);
    	for(int u=1;u<=n;u++)
    		for(int v=u*2;v<=n;v+=u)
    			createRect(u,v);
    	sort(a+1,a+1+acnt,cmp);
    	SEG::build(SEG::rt,1,n);
    	ll ans=1LL*n*(n+1)/2;
    	int lasty=0;
    	for(int i=1,j;i<=acnt;i=j){
    		ans-=1LL*(a[i].y-lasty)*SEG::query();
    		lasty=a[i].y;
    		for(j=i;j<=acnt&&a[j].y==a[i].y;j++)
    			SEG::modify(SEG::rt,1,n,a[j].l,a[j].r,a[j].d);
    	}
    	printf("%lld
    ",ans-n);
    	return 0;
    }
    
  • 相关阅读:
    POJ 3126 Prime Path
    POJ 2429 GCD & LCM Inverse
    POJ 2395 Out of Hay
    【Codeforces 105D】 Bag of mice
    【POJ 3071】 Football
    【POJ 2096】 Collecting Bugs
    【CQOI 2009】 余数之和
    【Codeforces 258E】 Devu and Flowers
    【SDOI 2010】 古代猪文
    【BZOJ 2982】 combination
  • 原文地址:https://www.cnblogs.com/RogerDTZ/p/8867192.html
Copyright © 2011-2022 走看看