Aug 24
这次比赛我依然是一如既往的唐诗...
后两道根本不是我能碰的,所以就不总结了,前两道题还是不错的,我先整理 T2,再整理 T1,毕竟我觉得 T2 比较简单。
我的统计方式似乎也是很为奇怪的。
因为今天晚上什么都不想干所以想尽可能写的详细一些。
T2
大概题意
给了一个 dfs 的方式
void dfs(int u) {
    vis[u] = true;
    for (int v = 1; v <= n; v++)
        if (g[u][v] == true && vis[v] == false)
            dfs(v), link(u, v);
}
这里的 g 就是我们常见的临接矩阵, link 表示把 u, v 之间加一条边。
容易发现,在 g 上最后我们会通过 link 连接出来一棵树。
现在我们的问题是给出来你这个树了,问你有几种不同的图的情况。
对于 1e9+7 取摸。
需要一个 O(nlogn)$ 的算法。
怎么做
我们首先根本不知道怎么直接去做这道题...
不知道怎么办?可以去尝试挖一挖性质。
明显我们的目的就是在这棵树上加入一些边,求出总数,并保证不影响正常的遍历。
现在我们尝试去寻找一些性质,会发现简单而且至关重要的性质。
- 
这些可能会被加入的边相互之间并不会相互影响,所以我们可以使用乘法原理,一个这样的边有在或不在两个状态,假设我们知道这样的边有 \(miao\) 条,一共就会有 \(2^{miao}\) 种方案。 
- 
一个可能被加入的边必须是从一个点连向她的祖先的,不然明显这个点会影响我们的遍历,注意我们统一采取从下到上的思考方式。 
我们思考一下这个边有什么具体的限制要求。
假设这个边是 \(A\to B\) 的。
首先 \(B\) 是 \(A\) 的祖先,这一点我们前边说过了。
我们现在需要考虑怎么加才能使得算法忽略掉这条边。
因为我们的算法总是会走小的,所以只要我们保证 \(A\) 比这个 \(B\) 的儿子要大,我们就可以做到跳过这条边正常向下了。
记下来。
- \(A>son[B]\)
注意这个 \(son\) 是 \(A\) 和 \(B\) 这一条链上的B的儿子,而不是通常意义上的那一堆儿子,特指这一个。
这样还没有完,看似我们已将问题讨论完了,然而我们仍然差了一个情况,玩意儿子和父亲自导自演呢?我们注意到有一种情况,即使满足上边的条件依然不能加,那就是他们是父子关系,中间是有直接连边的。
这个需要特判一下的啦。
- \(A!=son[B]\)
接下来就都是实现的问题啦。
这个问题是每一个点到根节点的问题,我们使用一个数据结构维护每个点到根的这条链。
简单说就是 dfs 的时候进入这个点的时候加入这个点的信息到数据结构里边,遍历完它的所有子树后,退出时删除它的信息。
我们以点的编号为下标建立一颗权值线段树,这样我们可以进行单点的修改和查询维护的链上比一个编号小的点数。
为了比较简洁,有艺术感的解决这个问题,我这个权值线段树维护的是这个 \(son\),也就是说每个点加进去并不代表自己,而是自己的父辈,自然我们特判一下是不是根节点,这样实现起来比较符合我的审美。
这个问题就这么轻松解决了,个人评价绿题,都很套路。
那为什么 BaiBaiShaFeng 在这道题上只有 75pts 呢?
那是因为智慧无双的白白杀疯对我们统计的边数直接取摸了,对幂次数取摸世界第一人,加上这个题数据非常的大的情况下真的有可能比 1e9+7 要大,导致有 25pts 的点直接就这么痛苦的消失了。
这启示我们把欧拉定理写在手上,锰缍兹季淂麽顽倚猈遐。
放一下我考场上美丽如艺术品的半压行马风。
代码如下
点击查看代码
#include <bits/stdc++.h>
#define int unsigned long long
using namespace std;
namespace DS{
	const int MN=1e6+116;
	struct MiaoMiaoTree{
		#define lc k<<1
		#define rc k<<1|1
		struct Node{
			int l, r, val;
		}tr[MN];
		void pushup(int k){
			tr[k].val=(tr[lc].val+tr[rc].val);
        }
		void build(int k, int l, int r){
			tr[k].l=l, tr[k].r=r;
			if(l==r){tr[k].val=0; return;}
			int mid=(tr[k].l+tr[k].r)>>1;
			build(lc,l,mid); build(rc,mid+1,r);
			pushup(k); return;
		}
		void update(int k, int pos, int val){
			if(tr[k].l==tr[k].r){
				tr[k].val+=val; return;
			}
			int mid=(tr[k].l+tr[k].r)>>1;
			if(pos<=mid) update(lc,pos,val);
			else update(rc,pos,val);
			pushup(k); return;
		}
		int query(int k, int l, int r){
			if(tr[k].l>=l&&tr[k].r<=r) return tr[k].val;
			int mid=(tr[k].l+tr[k].r)>>1,res=0;
			if(l<=mid) res+=query(lc,l,r);
			if(r>mid) res+=query(rc,l,r);
			return res;
		}
	};
}
namespace BaiBaiShaFeng{
	const int MN=1e6+116;
	const int mod=1e9+7;
	vector <int> G[MN];
	int n, ans=0;
	DS::MiaoMiaoTree tr;
	int quick_power(int a, int b, int mod){
		int res=1; a%=mod;
		while(b){
			if(b&1) res=(res*a)%mod;
			a=(a*a)%mod; b>>=1;}
		return res;
	}
	void dfs(int u, int father){
		if(u!=1){
			ans=(ans+tr.query(1,1,u-1));
		}
		if(u!=1) tr.update(1,u,1);
		for(auto v:G[u]){
			if(v==father) continue;
			dfs(v,u);
		}
		if(u!=1) tr.update(1,u,-1);
	}
	void solve(){
		cin>>n; tr.build(1,1,n);
		//cout<<"Miaop"<<'\n';
		for(int i=1,u,v; i<n; ++i){
			cin>>u>>v; G[u].emplace_back(v);
			G[v].emplace_back(u);
		}
		for(int i=1; i<=n; ++i) sort(G[i].begin(),G[i].end());
		dfs(1,1);
		cout<<quick_power(2,ans,mod)%mod<<'\n';
	}
}
signed main(){
	freopen("dfs.in","r",stdin);
	freopen("dfs.out","w",stdout);
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	BaiBaiShaFeng::solve(); return 0;
}

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号