2022 纪中集训7.7
T1
板子主席树
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
struct Node
{
int l,r;
int cnt;
}tr[N * 4 + N * 20];
int n,m;
int root[N],idx;
vector<int> num;
int a[N];
void pushup(int u)
{
tr[u].cnt = tr[tr[u].l].cnt + tr[tr[u].r].cnt;
}
int find(int x)
{
return lower_bound(num.begin(),num.end(),x) - num.begin();
}
int build(int l,int r)
{
int p = ++ idx;
if(l == r) return p;
int mid = l + r >> 1;
tr[p].l = build(l, mid) , tr[p].r = build(mid + 1,r);
return p;
}
int insert(int p,int l,int r,int x)
{
int q = ++ idx;
tr[q] = tr[p];
if(l == r)
{
tr[q].cnt ++;
return q;
}
int mid = l + r >> 1;
if(x <= mid) tr[q].l = insert(tr[p].l,l,mid,x);
else tr[q].r = insert(tr[p].r,mid+1,r,x);
pushup(q);
return q;
}
int L[N], R[N];
int K, P;
int query(int l,int r,int k)
{
if(l == r) return r;
int cnt = 0;
for(int i=1;i<=K;i++) cnt += tr[tr[R[i]].l].cnt - tr[tr[L[i]].l].cnt;
int mid = l + r >> 1;
if(k <= cnt)
{
for(int i=1;i<=K;i++) L[i] = tr[L[i]].l, R[i] = tr[R[i]].l;
return query(l,mid,k);
}
else
{
for(int i=1;i<=K;i++) L[i] = tr[L[i]].r, R[i] = tr[R[i]].r;
return query(mid+1,r,k-cnt);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
num.push_back(a[i]);
}
sort(num.begin(),num.end());
num.erase(unique(num.begin(),num.end()),num.end());
root[0] = build(0,num.size()-1);
for(int i=1;i<=n;i++) root[i] = insert(root[i-1],0,num.size()-1,find(a[i]));
// while(m --)
// {
// int l,r,k;
// scanf("%d%d%d",&l,&r,&k);
// printf("%d\n",num[query(root[r],root[l-1],0,num.size()-1,k)]);
// }
while(m --)
{
int x, y;
scanf("%d%d",&K,&P);
for(int i=1;i<=K;i++)
{
scanf("%d%d",&x,&y);
L[i] = root[x-1], R[i] = root[y];
}
printf("%d\n", num[query(0,num.size()-1,P)]);
}
return 0;
}
T2
树形DP
\(f[u][0]\) u的子树中没有黑点的代价
\(f[u][1]\) u的子树中没有白点的代价
\(f[u][i]\) u的子树中只有一个白点的代价
明显 \(f[u][2]\) 可以用 \(f[u][1]\) 减去最大的一条边得到。
赛时由于用了 dfs,爆栈了。。。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL, LL> PII;
const LL INF = 1e17;
const LL N=300010, M = 2*N;
LL n,root;
LL col[N],in[N];
LL f[N],g[N],h[N];
struct Edge
{
LL v,nxt;
LL w;
}e[M];
LL head[N], idx = 0;
void add(LL u,LL v,LL w=0)
{
e[++idx].v = v,e[idx].w = w, e[idx].nxt = head[u],head[u] = idx;
}
void bfs()
{
queue<LL> q;
for (LL i=1;i<=n;i++) if (in[i]==1) q.push(i);
while (q.size())
{
LL u=q.front();
q.pop();
root=u;
in[u]=0;
if (col[u]==0)
{
f[u]=INF;
for (LL i=head[u];i;i=e[i].nxt)
{
LL v=e[i].v;
if (!in[v]) g[u]+=min({f[v]+e[i].w,g[v],h[v]+e[i].w});
}
for (LL i=head[u];i;i=e[i].nxt)
{
LL v=e[i].v;
if (!in[v]) h[u]=min(h[u],h[v]+g[u]-min({f[v]+e[i].w,g[v],h[v]+e[i].w}));
}
}
if (col[u]==1)
{
g[u]=INF;
for (LL i=head[u];i;i=e[i].nxt)
{
LL v=e[i].v;
if (!in[v])
{
f[u]+=min({f[v],g[v]+e[i].w,h[v]+e[i].w});
h[u]+=min({f[v]+e[i].w,g[v],h[v]+e[i].w});
}
}
}
if (col[u]==2)
{
for (LL i=head[u];i;i=e[i].nxt)
{
LL v=e[i].v;
if (!in[v])
{
f[u]+=min({f[v],g[v]+e[i].w,h[v]+e[i].w});
g[u]+=min({f[v]+e[i].w,g[v],h[v]+e[i].w});
}
}
for (LL i=head[u];i;i=e[i].nxt)
{
LL v=e[i].v;
if (!in[v]) h[u]=min(h[u],h[v]+g[u]-min({f[v]+e[i].w,g[v],h[v]+e[i].w}));
}
}
for (LL i=head[u];i;i=e[i].nxt)
{
LL v=e[i].v;
if (in[v]>1)
{
in[v]--;
if (in[v]==1) q.push(v);
}
}
}
}
int main()
{
LL T;
scanf("%lld",&T);
while (T--)
{
memset(head,0,sizeof(head));
memset(in,0,sizeof(in));
idx=0;
scanf("%lld",&n);
for (LL i=1;i<=n;i++)
{
scanf("%lld",&col[i]);
if (col[i]==0) f[i]=INF,g[i]=0,h[i]=INF;
if (col[i]==1) f[i]=0,g[i]=INF,h[i]=0;
if (col[i]==2) f[i]=0,g[i]=0,h[i]=INF;
}
for (LL i=1;i<n;i++)
{
LL u,v,w;
scanf("%lld%lld%lld",&u,&v,&w);
add(u,v,w); add(v,u,w);
in[u]++; in[v]++;
}
bfs();
printf("%lld\n",min({f[root],g[root],h[root]}));
}
return 0;
}
T3
先跑一次最短路。
求出所以可能的最短路,并建图用作网络流。
跑最大流求最小割。
分别从起点和终点开始染色。
枚举残留网络中的跨两个块的边,统计边权。
若跨两个块的边权和不等于最小割的大小,则最小割不固定,方案不唯一。
反之亦然。
T4
FHQ-treap 维护
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
typedef long long LL;
struct FHQ
{
int l, r;
int size, key;
LL val, sum, pre, suc, maxn;
} fhq[N];
int n, m;
int rt = 0, cnt = 0;
int newnode(int val)
{
fhq[++cnt].size = 1;
fhq[cnt].sum = fhq[cnt].val = fhq[cnt].maxn = val;
fhq[cnt].pre = fhq[cnt].suc = max(0, val);
fhq[cnt].key = rand();
return cnt;
}
inline void pushup(int p)
{
int l = fhq[p].l, r = fhq[p].r;
fhq[p].size = fhq[l].size + fhq[r].size + 1;
fhq[p].sum = fhq[l].sum + fhq[r].sum + fhq[p].val;
fhq[p].pre = max(fhq[l].pre, fhq[l].sum + fhq[p].val + fhq[r].pre);
fhq[p].suc = max(fhq[r].suc, fhq[l].suc + fhq[p].val + fhq[r].sum);
fhq[p].maxn = max(fhq[l].suc + fhq[p].val + fhq[r].pre, max(fhq[l].maxn, fhq[r].maxn));
}
inline int merge(int x, int y)
{
if (!x || !y) return x | y;
if (fhq[x].key < fhq[y].key)
{
fhq[x].r = merge(fhq[x].r, y);
pushup(x);
return x;
}
else
{
fhq[y].l = merge(x, fhq[y].l);
pushup(y);
return y;
}
}
void split(int p, int sz, int &x, int &y)
{
if (!p)
x = y = 0;
else
{
if (fhq[fhq[p].l].size < sz)
{
x = p;
split(fhq[p].r, sz - fhq[fhq[p].l].size - 1, fhq[p].r, y);
}
else
{
y = p;
split(fhq[p].l, sz, x, fhq[p].l);
}
pushup(p);
}
}
int main()
{
srand(114514);
scanf("%d",&n);
fhq[0].maxn = -1e9;
for (int i = 1, x; i <= n; ++i)
{
scanf("%d",&x);
rt = merge(rt, newnode(x));
}
scanf("%d",&m);
char op[3];
int a, b, x, y, z;
while (m--)
{
scanf("%s%d", op, &a);
if (op[0] == 'I')
{
scanf("%d",&b);
split(rt, a - 1, x, y);
rt = merge(x, merge(newnode(b), y));
}
if (op[0] == 'D')
{
split(rt, a - 1, x, y);
split(y, 1, y, z);
rt = merge(x, z);
}
if (op[0] == 'R')
{
scanf("%d",&b);
split(rt, a - 1, x, y);
split(y, 1, y, z);
fhq[y].sum = fhq[y].val = fhq[y].maxn = b;
fhq[y].pre = fhq[y].suc = max(b, 0);
rt = merge(x, merge(y, z));
}
if(op[0] == 'Q')
{
scanf("%d",&b);
split(rt, b, y, z);
split(y, a - 1, x, y);
printf("%lld\n", fhq[y].maxn);
rt = merge(x, merge(y, z));
}
}
return 0;
}