思路:我们用一颗最小值线段树存 a 数组,枚举 b 数组,假设当前枚举到了 bi,我们先找到 a 数组中第一个等于 bi 的值的下标 k,然后在线段树中查询[1, k]最小值,如果最小值 < bi,就说明,k 前面有比 ak 小的数导致 ak 不能顺利的移动到和 bi 匹配的位置,无解,如果有解,就继续枚举 bi+1,并且把线段树中 k 点权值清空
#include<bits/stdc++.h>#define ll long long
using namespace std;constint maxn =3e5+10;int a[maxn], b[maxn];int mn[maxn *4];voidup(int o,int l,int r,int k,int v){if(l == r){
mn[o]= v;return;}int m =(l + r)/2, ls = o *2, rs = o *2+1;if(k <= m)up(ls, l, m, k, v);elseup(rs, m +1, r, k, v);
mn[o]=min(mn[ls], mn[rs]);}intqu(int o,int l,int r,int ql,int qr){if(l >= ql && r <= qr)return mn[o];int m =(l + r)/2, ls = o *2, rs = o *2+1, res =1e9;if(ql <= m)
res =min(res,qu(ls, l, m, ql, qr));if(qr > m)
res =min(res,qu(rs, m +1, r, ql, qr));return res;}
queue<int> q[maxn];intmain(){int T;scanf("%d",&T);while(T--){int n, x;scanf("%d",&n);for(int i =1; i <= n; i++){scanf("%d",&a[i]);
q[a[i]].push(i);up(1,1, n, i, a[i]);}int flag =1;for(int i =1; i <= n; i++){scanf("%d",&x);if(!q[x].empty()){int k = q[x].front();
q[x].pop();if(qu(1,1, n,1, k)< x)
flag =0;elseup(1,1, n, k,1e9);}else
flag =0;}for(int i =1; i <= n; i++)while(!q[a[i]].empty())
q[a[i]].pop();if(flag)puts("YES");elseputs("NO");}}
思路:我们发现如果我们定好了第一个,那么总权值是一个定值,那么问题转化为,枚举每一个点为涂色起点所能获得的总权值,答案是最大的那个,设d[u] 为 u 子树中,先涂 u 点所能获得的总权值,sz[u] 为 u 子树大小,那么转移方程:d[u] = d[son] + sz[u],我们先一遍dfs求出以 1 为根且为涂色起点的答案,接下来再用一个dfs进行换根dp,对于 u 的儿子 v,我们要把根转移到 v,首先断开u v 的连接:d[u] =d[u] - sz[v] -d[v],然后以 v 为根再连接:d[v] += d[u] + n - sz[v]。
#include<bits/stdc++.h>#define pb push_back#define ll long long
using namespace std;constint maxn =2e5+10;
vector<int> G[maxn];
ll d[maxn], ans;int n, sz[maxn];voiddfs(int u,int fa){
sz[u]=1;for(auto v : G[u]){if(v == fa)continue;dfs(v, u);
sz[u]+= sz[v];
d[u]+= d[v];}
d[u]+= sz[u];}voiddfs2(int u,int fa){
ans =max(ans, d[u]);for(auto v : G[u]){if(v == fa)continue;
ll tmp = d[u]- d[v]- sz[v];
d[v]= d[v]+(n - sz[v])+ tmp;dfs2(v, u);}}intmain(){int u, v;
cin>>n;for(int i =1; i < n; i++){
cin>>u>>v;
G[u].pb(v);
G[v].pb(u);}dfs(1,0);dfs2(1,0);
cout<<ans;}
D. Subarray Sorting题意:给你两个数组a,b,你可以在第一个数组里面任意取一些区间进行排序,问是否能够把数组a变成数组b。思路:我们用一颗最小值线段树存 a 数组,枚举 b 数组,假设当前枚举到了 bi,我们先找到 a 数组中第一个等于 bi 的值的下标 k,然后在线段树中查询[1, k]最小值,如果最小值 < bi,就说明,k 前面有比 ak 小的数导致 ak ...