2022 纪中集训7.7

T1

image

板子主席树

#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

image
树形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

image
先跑一次最短路。
求出所以可能的最短路,并建图用作网络流。
跑最大流求最小割。
分别从起点和终点开始染色。
枚举残留网络中的跨两个块的边,统计边权。
若跨两个块的边权和不等于最小割的大小,则最小割不固定,方案不唯一。
反之亦然。

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;
}
posted @ 2022-07-07 16:41  BorisDimitri  阅读(16)  评论(0编辑  收藏  举报