#include<bits/stdc++.h>#define ll long long
using namespace std;constint maxn =2005, mod =1e9+7;
ll dp[2][maxn];voidadd(ll &x, ll y){
x += y;if(x >= mod)
x -= mod;}intmain(){int n, h, x, cur =0;
cin>>n>>h>>x;if(x == h || x == h -1)
dp[cur][0]=1;if(x == h -1)
dp[cur][1]=1;while(--n){
cin>>x;
cur =!cur;memset(dp[cur],0,sizeof(dp[cur]));int i = h - x -1;for(int j =max(0, i); j <= i +1; j++){if(j + x == h){add(dp[cur][j], dp[!cur][j]);add(dp[cur][j], dp[!cur][j -1]);}if( j + x == h -1){add(dp[cur][j], dp[!cur][j +1]*(j +1)% mod);add(dp[cur][j], dp[!cur][j]*(j +1)% mod);}}}
cout<<dp[cur][0];}
题意:有三种操作:1 x y :将x的父亲设为y(保证之前x没有父亲),2 x :新增了一份文件,x 到 x当前的根路径上所有节点都会接受这份文件,3 x i:询问x是否收到了第 i 份文件
思路:对于每一份文件,我都存好接受这份文件的的 x 节点和 x 的根节点 rt,那么问题转化成:查询 y 节点是否在 x 到 rt 的路径中,我们先对每颗树进行dfs序,设L[u]为u的dfs序,R[u]为u的子树中节点中最大的dfs序,如果 y 是 x 的祖先,那么显然满足一个条件:L[y] <= L[x] && R[y] >= R[x],那么根据这个性质,就可以解决掉这个题了
#include<bits/stdc++.h>#define mk make_pair#define pb push_back#define pi pair<int, int>
using namespace std;constint maxn =1e5+10;
vector<int> G[maxn];
pi val[maxn];int L[maxn], R[maxn], p[maxn], cnt;struct node {int opt, x, y;}a[maxn];intfind(int x){if(p[x]!= x)
p[x]=find(p[x]);return p[x];}voiddfs(int u){
L[u]=++cnt;for(auto v : G[u])dfs(v);
R[u]= cnt;}intmain(){int n, q, num =0;
cin>>n>>q;for(int i =1; i <= n; i++)
p[i]= i;for(int i =1; i <= q; i++){
cin>>a[i].opt>>a[i].x;if(a[i].opt ==1){
cin>>a[i].y;
G[a[i].y].pb(a[i].x);int x =find(a[i].x);int y =find(a[i].y);
p[x]= y;}elseif(a[i].opt ==2){
num++;int y =find(a[i].x);
val[num]=mk(a[i].x, y);}else
cin>>a[i].y;}for(int i =1; i <= n; i++)if(!L[i]){int root =find(i);dfs(root);}for(int i =1; i <= q; i++){if(a[i].opt !=3)continue;int cur = a[i].y;int x = val[cur].first;int rt = val[cur].second;int o = a[i].x;if(L[o]<= L[x]&& R[o]>= R[x]&& L[rt]<= L[o]&& R[rt]>= R[o])puts("YES");elseputs("NO");}}