NOIP模拟(11.07)T3 图

题目背景:

11.06 NOIP模拟T3

分析:LCT or 暴力

 

这个题,上来就是50分暴力然后就没有然后了······

讲题,首先我们可以知道最后的最小生成树上的边,要么是A种边建成的最小生成树上的边,要么是B种边建成的最小生成树上的边,否则肯定不对,显然当x为无穷小的时候,最小生成树就是A种边构出的最小生成树,那么随着x的增大,B种边会不断的取代B种边,考虑不同的B种边取代A种边的时间。首先如果两条B边在不同的A边形成的环上,那么这两条边的取代时间互不影响,如果这两条边在现在覆盖到了相同的A边的环,那么肯定是小一些的那一条先进入最小生成树,那么到这里就比较清楚了,我们先对A边和B边各求一个最小生成树,然后从小到大枚举B树的边然后考虑替换掉当前环上k值最大的A边,然后记录替换的x值,最后按替换的x值排序从小到大更改贡献即可。加边删边可以通过LCT来维护,但是暴力跑的比LCT快,因为正解是个随机数据······

 

正解:

Source:

/*
	created by scarlyw
*/
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <ctime>

inline char read() {
	static const int IN_LEN = 1024 * 1024;
	static char buf[IN_LEN], *s, *t;
	if (s == t) {
		t = (s = buf) + fread(buf, 1, IN_LEN, stdin);
		if (s == t) return -1;
	}
	return *s++;
}

template<class T>
inline void R(T &x) {
	static char c;
	static bool iosig;
	for (c = read(), iosig = false; !isdigit(c); c = read()) {
		if (c == -1) return ;
		if (c == '-') iosig = true;
	}
	for (x = 0; isdigit(c); c = read())
		x = ((x << 2) + x << 1) + (c ^ '0');
	if (iosig) x = -x;
}

const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN], *oh = obuf;
inline void write_char(char c) {
	if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;
	*oh++ = c;
}

template<class T>
inline void W(T x) {
	static int buf[30], cnt;
	if (x == 0) write_char('0');
	else {
		if (x < 0) write_char('-'), x = -x;
		for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
		while (cnt) write_char(buf[cnt--]);
	}
}

inline void flush() {
	fwrite(obuf, 1, oh - obuf, stdout);
}

const int MAXN = 100000 + 10;
const int MAXM = 200000 + 10;
const int INF = 2000000000;

long long mst;
long long ans[MAXN];

int w[MAXM];
struct edges {
	int u, v, w;
	inline bool operator < (const edges &a) const {
		return w < a.w;
	}
} a[MAXM], b[MAXM], ta[MAXN], tb[MAXN];

struct node *null;
struct node {
	node *c[2], *fa, *pa;
	int max, val, rank, size;
	bool rev;
	
	node() {}
	node(int val) : fa(null), pa(null), max(val), val(val), rank(rand()), 
		size(1), rev(false) {
		c[0] = c[1] = null;
	}
	
	inline void reverse() {
		std::swap(c[0], c[1]), rev ^= 1;
	}
	
	inline void push_down() {
		if (this == null) return ;
		if (rev) c[0]->reverse(), c[1]->reverse(), rev ^= 1;
	}
	
	inline void maintain() {
		if (this == null) return ;
		size = c[0]->size + c[1]->size + 1;
		max = val;
		if (w[c[0]->max] > w[max]) max = c[0]->max;
		if (w[c[1]->max] > w[max]) max = c[1]->max;
	}
	
	inline int relation() {
		return this == fa->c[1];
	}
	
	inline void rotate() {
		push_down();
		node *old_fa = fa;
		int x = relation();
		pa = fa->pa, fa->pa = null;
		if (old_fa->fa != null) old_fa->fa->c[old_fa->relation()] = this;
		fa = old_fa->fa, old_fa->c[x] = c[x ^ 1];
		if (c[x ^ 1] != null) c[x ^ 1]->fa = old_fa;
		c[x ^ 1] = old_fa, old_fa->fa = this, old_fa->maintain(), maintain();
	}
	
	inline void splay(node *target = null) {
		while (fa != target) {
			fa->fa->push_down(), fa->push_down();
			if (fa->fa == target) rotate();
			else if (fa->relation() == relation()) fa->rotate(), rotate();
			else rotate(), rotate();
		}
		push_down();
	}
	
	inline void expose() {
		splay();
		if (c[1] != null) 
			c[1]->pa = this, c[1]->fa = null, c[1] = null, maintain();
	}
	
	inline bool splice() {
		expose();
		if (pa == null) return false;
		pa->expose(), pa->c[1] = this, fa = pa, pa = null, fa->maintain();
		return true;
	}
	
	inline void access() {
		expose();
		while (splice());
		splay();
	}
	
	inline void evert() {
		access(), reverse();
	}
} point[MAXN << 1];

inline void link(node *u, node *v) {
	u->evert(), u->pa = v;
}

inline void cut(node *u, node *v) {
	u->evert(), v->access(), v->c[0] = null, u->fa = null, u->maintain();
}

inline int query_max(node *u, node *v) {
	return u->evert(), v->access(), v->max;
}

struct query {
	int x, id;
	inline bool operator < (const query &a) const {
		return x < a.x;
	}
} q[MAXN];

int n, A, B, m;
int father[MAXN];
inline void read_in() {
	R(n), R(A), R(B), R(m);
	for (int i = 1; i <= A; ++i) R(a[i].u), R(a[i].v), R(a[i].w);
	for (int i = 1; i <= B; ++i) R(b[i].u), R(b[i].v), R(b[i].w);
	for (int i = 1; i <= m; ++i) R(q[i].x), q[i].id = i;
}

inline int get_father(int x) {
	return (father[x] == x) ? (x) : (father[x] = get_father(father[x]));
}
 
inline void kruscal(edges *e, int m, edges *new_e) {
	std::sort(e + 1, e + m + 1);
	for (int i = 1; i <= n; ++i) father[i] = i;
	int cnt = 0;
	for (int i = 1; i <= m; ++i) { 
		int x = e[i].u, y = e[i].v, fa1 = get_father(x), fa2 = get_father(y);
		if (fa1 != fa2) {
			father[fa1] = fa2, new_e[++cnt] = e[i];
			if (cnt == n - 1) break ;
		}
	}
}

struct data {
	int a, b, x;
	data() {}
	data(int a, int b, int x) : a(a), b(b), x(x) {}
	inline bool operator < (const data &c) const {
		return x < c.x;
	}
} modify[MAXN];

inline void solve() {
	null = &point[0], null->fa = null->pa = null->c[0] = null->c[1] = null;
	null->size = null->val = null->max = null->rev = 0;
	read_in(), kruscal(a, A, ta), kruscal(b, B, tb), w[0] = -INF;
	for (int i = 1; i <= n; ++i) point[i] = node(0);
	for (int i = 1; i < n; ++i) w[i] = ta[i].w;
	for (int i = 1; i < n; ++i) {
		point[i + n] = node(i), mst += (long long)ta[i].w;
		link(&point[ta[i].u], &point[i + n]);
		link(&point[ta[i].v], &point[i + n]);
	}
	for (int i = 1; i < n; ++i) {
		int x = tb[i].u, y = tb[i].v, cur = query_max(&point[x], &point[y]);
		modify[i] = data(w[cur], tb[i].w, (tb[i].w - w[cur] + 1) / 2);
		cut(&point[ta[cur].u], &point[cur + n]);
		cut(&point[ta[cur].v], &point[cur + n]);
		link(&point[y], &point[x]);		
	}
	std::sort(q + 1, q + m + 1), std::sort(modify + 1, modify + n);
	for (int i = 1, head = 1; i <= m; ++i) {
		while (head < n && modify[head].x <= q[i].x) {
			mst -= (long long)modify[head].a, mst += (long long)modify[head].b;
			head++;
		}
		ans[q[i].id] = mst - (long long)(head - 1) * q[i].x + 
			(long long)(n - head) * q[i].x;
	}
	for (int i = 1; i <= m; ++i) W(ans[i]), write_char('\n');
}

int main() {
	solve();
	flush();
	return 0;
}

暴力(orz DZYO dalao)

Source:

//duzhenyu

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	char ch=getchar();int i=0,f=1;
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();}
	return i*f;
}
inline void W(long long x){
	static int buf[50];
	if(!x){putchar('0');return;}
	if(x<0){putchar('-');x=-x;}
	while(x){buf[++buf[0]]=x%10;x/=10;}
	while(buf[0])putchar(buf[buf[0]--]+'0');
}
const int Maxn=1e5+50; 
const int INF=0x3f3f3f3f;
int n,Acnt,Bcnt,q,anc[Maxn],ht[Maxn],fa[Maxn];
long long ans[Maxn],sum;
struct E{
	int x,y,w;
	friend inline bool operator <(const E &a,const E &b){
		return a.w<b.w;
	} 
}A[Maxn<<1],B[Maxn<<1];
struct E2{
	int x,y,w,low,rpc;
	inline bool operator =(const E &b){
		x=b.x,y=b.y,w=b.w;
	}
}Bnow[Maxn];
struct Q{
	int v,id;
}qry[Maxn];
inline bool cmpv(const Q &a,const Q &b){return a.v<b.v;}
inline bool cmpw(const E2 &a,const E2 &b){return a.w<b.w;}
inline bool cmplow(const E2 &a,const E2 &b){return a.low<b.low;}
inline int getanc(int x){return (anc[x]==x)?(x):(anc[x]=getanc(anc[x]));}
typedef pair<int,int> pii;
inline void makeroot(int x){
	static int st[Maxn],w[Maxn],tail;
	st[tail=1]=x;
	while(fa[x]){
		st[++tail]=fa[x];w[tail]=ht[x];x=fa[x];
	} 
	for(int i=tail;i>1;i--)
		fa[st[i]]=st[i-1],ht[st[i]]=w[i];
	fa[st[1]]=0;
}
inline void Link(int x,int y,int val){
	makeroot(x);
	fa[x]=y;ht[x]=val;
}
inline pii findmx(int x,int y){
	static int vis[Maxn],vt;
	++vt;int mx=-INF,mxid=0,xtmp=x,ytmp=y;
	while(fa[xtmp]){
		vis[xtmp]=vt;
		xtmp=fa[xtmp];
	} 
	while(fa[ytmp]){
		if(vis[ytmp]==vt)break;
		if(ht[ytmp]>mx)mx=ht[ytmp],mxid=ytmp;
		ytmp=fa[ytmp];
	}
	++vt;xtmp=y,ytmp=x;
	while(fa[xtmp]){
		vis[xtmp]=vt;
		xtmp=fa[xtmp];
	} 
	while(fa[ytmp]){
		if(vis[ytmp]==vt)break;
		if(ht[ytmp]>mx)mx=ht[ytmp],mxid=ytmp;
		ytmp=fa[ytmp];
	}
	return make_pair(mx,mxid);
}
int main(){
	freopen("mst.in","r",stdin);
	freopen("mst.out","w",stdout);
	n=read(),Acnt=read(),Bcnt=read(),q=read();
	for(int i=1;i<=Acnt;i++){
		A[i].x=read(),A[i].y=read(),A[i].w=read();
	}
	for(int i=1;i<=Bcnt;i++){
		B[i].x=read(),B[i].y=read(),B[i].w=read();
	}
	sort(A+1,A+Acnt+1);sort(B+1,B+Bcnt+1);
	int head=1;
	for(int i=1;i<=n;i++)anc[i]=i;
	for(int i=1;i<n;i++){
		while(getanc(A[head].x)==getanc(A[head].y))++head;
		anc[getanc(A[head].x)]=getanc(A[head].y);
		Link(A[head].x,A[head].y,A[head].w);
		sum+=A[head].w;++head;
	}
	head=1;int tot=0;
	for(int i=1;i<=n;i++)anc[i]=i;
	for(int i=1;i<n;i++){
		while(getanc(B[head].x)==getanc(B[head].y))++head;
		anc[getanc(B[head].x)]=getanc(B[head].y);
		Bnow[i]=B[head++];
	}
	sort(Bnow+1,Bnow+tot+1,cmpw);
	for(int i=1;i<n;i++){
		pii t=findmx(Bnow[i].x,Bnow[i].y);
		if(t.second<=-INF){Bnow[i].low=INF;}
		else{
			Bnow[i].low=(Bnow[i].w-t.first+1)/2;
			Bnow[i].rpc=t.first;
			fa[t.second]=0;ht[t.second]=0;
			Link(Bnow[i].x,Bnow[i].y,-INF);
		}
	}
	sort(Bnow+1,Bnow+n,cmplow);
	for(int i=1;i<=q;i++)qry[i].v=read(),qry[i].id=i;
	sort(qry+1,qry+q+1,cmpv);
	int cntB=0;head=0;
	for(int i=1;i<=q;i++){
		while(head<n-1&&Bnow[head+1].low<=qry[i].v){
			++head;cntB++;
			sum+=Bnow[head].w;sum-=Bnow[head].rpc;
		}
		ans[qry[i].id]=sum+1ll*(n-1-2*cntB)*qry[i].v;
	}
	for(int i=1;i<=q;i++){
		W(ans[i]);putchar('\n');
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值