• FZOJ 4267 树上统计


    对每一条边单独考虑其贡献。

    我们现在想算有多少连续区间跨过了这条边。正难则反,我们考虑有多少连续区间不跨过这条边,最后用总的减去这些。所以我们只需要计算当前子树内和子树外的连续区间的贡献就行。

    考虑 dsu on tree。子树内用并查集维护并计算极长子段的贡献,子树外用set维护其补集并计算贡献即可。

    代码:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<set>
    #define int long long
    #define S_IT set <int> ::iterator
    
    using namespace std;
    
    const int N=100009;
    set <int> S;
    int head[N],cnt,bin[N],son[N],siz[N],L[N],R[N],Index,rev[N],n,ans,ans_In,ans_Out;
    struct Edge
    {
    	int nxt,to;
    }g[N*2];
    struct Union
    {
    	int fa[N];
    	
    	int find(int x)
    	{
    		if(fa[x]==x)
    			return x;
    		return fa[x]=find(fa[x]);
    	}
    	
    	void merge(int x,int y)
    	{
    		int X=find(x),Y=find(y);
    		if(X!=Y)
    		{
    			fa[Y]=X;
    			bin[X]+=bin[Y];
    		}
    	}
    }B;
    
    void add(int from,int to)
    {
    	g[++cnt].nxt=head[from];
    	g[cnt].to=to;
    	head[from]=cnt;
    }
    
    void init()
    {
    	scanf("%lld",&n);
    	for (int x,y,i=1;i<n;i++)
    		scanf("%lld %lld",&x,&y),
    		add(x,y),add(y,x);
    }
    
    void dfs(int x,int fa)
    {
    	siz[x]=1,L[x]=++Index,rev[Index]=x;
    //	printf("%lld %lld
    ",x,fa);
    	for (int i=head[x];i;i=g[i].nxt)
    	{
    		int v=g[i].to;
    		if(v==fa)
    			continue;
    		dfs(v,x);
    		siz[x]+=siz[v];
    		if(siz[v]>siz[son[x]])
    			son[x]=v;
    	}
    	R[x]=Index;
    }
    
    int calc(int x) { return x*(x+1)/2; }
    
    void Insert(int x)
    {
    	bin[x]=1;
    	if(x>1&&bin[x-1])
    		ans_In-=calc(bin[B.find(x-1)]),
    		B.merge(x,x-1);
    	if(x<n&&bin[x+1])
    		ans_In-=calc(bin[B.find(x+1)]),
    		B.merge(x,x+1);
    	ans_In+=calc(bin[B.find(x)]);
    	S_IT it=S.insert(x).first;
    	S_IT it1=it,it2=it;
    	it1--,it2++;
    	ans_Out=ans_Out-calc(*it2-*it1-1)+calc(*it-*it1-1)+calc(*it2-*it-1);
    }
    
    void DFS(int x,int fa)
    {
    	for (int i=head[x];i;i=g[i].nxt)
    	{
    		int v=g[i].to;
    		if(v==fa||v==son[x])
    			continue;
    		DFS(v,x);
    		ans_In=0,ans_Out=calc(n);
    		for (int j=L[v];j<=R[v];j++)
    		{
    			int J=rev[j];
    			bin[J]=0,S.erase(J),B.fa[J]=J;
    		}
    	}
    	if(son[x])
    		DFS(son[x],x);
    	Insert(x);
    	for (int i=head[x];i;i=g[i].nxt)
    	{
    		int v=g[i].to;
    		if(v==fa||v==son[x])
    			continue;
    		for (int j=L[v];j<=R[v];j++)
    			Insert(rev[j]);
    	}
    	ans+=calc(n)-ans_In-ans_Out;
    }
    
    void work()
    {
    	dfs(1,-1);
    	S.insert(0),S.insert(n+1);
    	for (int i=1;i<=n;i++)
    		B.fa[i]=i;
    	ans_Out=calc(n);
    	DFS(1,-1);
    	printf("%lld
    ",ans);
    }
    
    signed main()
    {
    	init();
    	work();
    	return 0;
    }
    
    由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!
  • 相关阅读:
    Linux下如何查看版本信息
    linux的top命令参数详解
    浅谈Linux内存管理机制
    python3 判断字符串是否为纯空格组成的方法
    python3 字符串/列表/元组(str/list/tuple)相互转换方法及join()函数的使用
    python3 json数据格式的转换(dumps/loads的使用、dict to str/str to dict、json字符串/字典的相互转换)
    python3 list列表随机选取一个元素、随机选择一个user-agent
    windows系统中,在当前目录下打开cmd命令行的两种方法
    name 'reload' is not defined解决方法
    Vue.js05:vue内联样式
  • 原文地址:https://www.cnblogs.com/With-penguin/p/13288429.html
Copyright © 2020-2023  润新知