zoukankan      html  css  js  c++  java
  • [APIO2018] Duathlon 铁人两项

    考虑建出圆方树。
    那么如果我们固定两点,对答案的贡献是两个点之间的点数减去\(2\)
    那么我们考虑在圆方树上做。
    把方点的权值设为该点双的大小,把圆点设为\(-1\)
    则统计任意两圆点间的点权和。
    拆成单点贡献就好了。
    另外注意在建圆方树时,\(u\)\(v\)在栈中不一定相邻,要退栈到\(v\),单独考虑\(u\)

    [APIO2018] Duathlon 铁人两项
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<stack>
    #define ll long long
    #define N 400000
    
    struct P{int to,next;};
    
    struct Map{
    	P e[N];
    	int cnt,head[N];
    	Map(){
    		cnt = 0;
    		std::memset(head,0,sizeof(head));
    	}
    	inline void add(int x,int y){		
    		e[++cnt].to = y;
    		e[cnt].next = head[x];
    		head[x] = cnt;
    	}
    }A,T;
    
    ll n,m;
    ll dfn[N],dfncnt,low[N],siz[N];
    
    std::stack<int>QWQ;
    
    ll vi[N],fcnt,num;
    
    inline void tarjan(int u){
    	vi[u] = -1;
    	dfn[u] = low[u] = ++dfncnt;
    	QWQ.push(u);
    	++num;
    	for(int i = A.head[u];i;i = A.e[i].next){
    		int v = A.e[i].to;
    		if(!dfn[v]){
    			tarjan(v);
    			low[u] = std::min(low[u],low[v]);
    			if(low[v] == dfn[u]){
    				vi[++fcnt] = 0;
    //				std::cout<<fcnt<<":"<<std::endl;
    				while(QWQ.top() != v){
    //					std::cout<<QWQ.top()<<std::endl;
    					T.add(QWQ.top(),fcnt);
    					T.add(fcnt,QWQ.top());
    					++vi[fcnt];
    					QWQ.pop();
    				}
    //				std::cout<<QWQ.top()<<std::endl;				
    				T.add(QWQ.top(),fcnt);
    				T.add(fcnt,QWQ.top());
    				++vi[fcnt];
    				QWQ.pop();
    				T.add(u,fcnt);
    				T.add(fcnt,u);		
    				++vi[fcnt];
    			}
    		}
    		else
    		low[u] = std::min(low[u],dfn[v]);
    	}
    }
    
    ll ans = 0;
    
    inline void dfs(int u,int fa){
    	siz[u] = (u <= n);
    	for(int i = T.head[u];i;i = T.e[i].next){
    		int v = T.e[i].to;
    		if(v == fa)
    		continue;
    		dfs(v,u);
    		ans += 2 * vi[u] * siz[u] * siz[v];//子树间。 
    		siz[u] += siz[v];
    	}
    	ans += 2 * siz[u] * vi[u] * (num - siz[u]);//祖先和子树。 
    }
    
    int main(){
    	scanf("%lld%lld",&n,&m);
    	fcnt = n;
    	for(int i = 1;i <= m;++i){
    		int x,y;
    		scanf("%d%d",&x,&y);
    		A.add(x,y);
    		A.add(y,x);
    	}
    	for(int i = 1;i <= n;++i)
    	if(!dfn[i])
    	num = 0,tarjan(i),dfs(i,0);
    	std::cout<<ans<<std::endl;
    }
    
  • 相关阅读:
    servlet
    过滤器
    拦截器
    logback
    hibernate(1)
    函数的关键字参数
    函数的不定长参数
    打印星形三角
    九九乘法表
    udp客户端收发数据流程
  • 原文地址:https://www.cnblogs.com/dixiao/p/14728330.html
Copyright © 2011-2022 走看看