谎言 欺骗 鄙夷 如破碎瓦砾铺满地 利用陷害窒息莫名遭受唾骂遗弃

test25

一本通tour

把边当作点,连像传递奖牌的另一个点,每一个奖牌经过一条树上到根的链,直接深搜+set 即可查询出在谁那里呆的最久。

#include<bits/stdc++.h>
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define pb push_back

using namespace std;

const int N=200005;

int n, m, x[N], y[N], lst[N], fa[N], val[N], Ans[N];
vector<int> to[N];
struct node {
	int u, cnt;
	bool operator<(const node &rhs) const {
		if(cnt!=rhs.cnt) return cnt>rhs.cnt;
		return u<rhs.u; 
	}
};
multiset<node> qwq;

void dfs(int x) {
	int i=y[x];
	qwq.erase((node){i,val[i]});
	val[i]+=(fa[x]?fa[x]:m+1)-x;
	qwq.insert((node){i,val[i]});
	
	++Ans[(*qwq.begin()).u];
	
	for(int y:to[x]) dfs(y);
	
	qwq.erase((node){i,val[i]});
	val[i]-=(fa[x]?fa[x]:m+1)-x;
	qwq.insert((node){i,val[i]});
}

signed main() {
	freopen("ybt.in","r",stdin); 
	freopen("ybt.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> m;
	up(i,1,m) cin >> y[i] >> x[i], ++x[i], ++y[i];
	dn(i,m,1) {
		if(lst[y[i]]) {
			fa[i]=lst[y[i]];
			to[lst[y[i]]].pb(i);
		}
		lst[x[i]]=i;
	}
	up(i,1,n) qwq.insert((node){i,0});
	up(i,1,m) if(!fa[i]) qwq.clear(), dfs(i);
	up(i,1,n) cout << Ans[i] << ' ';
	return 0;
}

洛谷luogu

没有奇环就是二分图,但是带着二分属性不好做。不妨考虑随机染色然后暴力 dp,正确的概率大于 \(\frac{1}{2^9}\),不妨认为随机 \(2^{k-1}\) 正确的概率是 \(\frac{1}{2}\),那么随机 \(2^{k-1}\times 30\) 次错误率不超过 \(\frac{1}{2^{30}}\)

#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define min(a,b) ((a)<(b)?(a):(b))
#define pb push_back

using namespace std;

const int N=85, M=15, inf=1e18;

int n, k, dis[N][N], Ans=inf, gp[N], f[M][N];

signed main() {
	freopen("luogu.in","r",stdin); 
	freopen("luogu.out","w",stdout);
    mt19937_64 rd(chrono::steady_clock::now().time_since_epoch().count());
	chrono::steady_clock::now().time_since_epoch().count();
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> k;
	up(i,1,n) up(j,1,n) cin >> dis[i][j];
	int T=37*(1<<(k-1));
	up(t,1,T) {
		up(i,2,n) gp[i]=rd()&1;
		up(i,2,n) f[0][i]=inf;
		up(u,1,k) {
			up(i,1,n) if(gp[i]==(u&1)) {
				f[u][i]=inf;
				up(j,1,n) if(gp[j]!=(u&1)) {
					f[u][i]=min(f[u][i],f[u-1][j]+dis[j][i]);
				}
			}
		}
		Ans=min(Ans,f[k][1]);
	}
	cout << Ans << '\n';
	return 0;
}

2023年的NOIselfEval

弹飞绵羊来的,考虑分块,维护每个点跳出本块之后会到哪、要几步。这样子更新和查询都是 \(O(\sqrt n)\) 的了,而且常数很小。

#include<bits/stdc++.h>
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)

using namespace std;

const int N=200005;

int n, m, B, val[N], to[N], run[N];

void build(int l,int r) {
	dn(i,r,l) {
		if(i+val[i]>r) to[i]=-1, run[i]=1;
		else to[i]=to[i+val[i]], run[i]=run[i+val[i]]+1;
	}
}

signed main() {
//	freopen("1.txt","r",stdin);
	freopen("selfeval.in","r",stdin); 
	freopen("selfeval.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n, B=sqrt(n);
	up(i,0,n-1) cin >> val[i];
	up(u,0,(n-1)/B) build(B*u,min(B*(u+1)-1,n-1));
	cin >> m;
	while(m--) {
		int opt, i, v=0;
		cin >> opt >> i;
		if(opt==1) {
			for( ; i<n; ) {
				if(to[i]==-1) i=i+val[i], ++v;
				else v+=run[i], i=to[i];
			}
			cout << v << '\n';
		}
		else {
			cin >> v, val[i]=v;
			build(B*(i/B),min(B*((i/B)+1)-1,n-1));
		}
	}
	return 0;
}

如果你能去 IOI CMS

先考虑一下题目求的是啥,切成 \(k+1\) 棵树求直径和,也就是选择恰好 \(k+1\) 条不相交的路径问权值和最大是多少咯。考虑 \(k+1=1\to n\) 的过程,先可以且更多的树拿更多的路径,然后会被迫去切开拿来贡献的边,直接上 wqs 二分,其实凸性不轻易严谨证明、但是单调性可以。

之后问题变成了取一条链会额外花费 \(\Delta\),问选若干条链贡献和最大是多少。考虑怎么描述状态,考虑 \(f_{x,0/1}\) 表示子树到根向上传递和子树不向上传递的答案,转移是容易的。

#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define pii pair<int,int>
#define pb push_back 
#define mp make_pair

using namespace std;

inline int read() {
    int X=0; bool flag=1; char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
    while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
    if(flag) return X;
    return ~(X-1);
}

const int N=300005;

int n, k, Pluto;
vector<pii> to[N];

struct data {
	int val, cnt;
	bool operator<(const data &rhs) const { return val==rhs.val?cnt>rhs.cnt:val<rhs.val; }
} f[N][3], nul, tmp;

data operator+(data x,data y) { return (data){x.val+y.val,x.cnt+y.cnt}; }
data operator+(data x,int num) { return (data){x.val+num,x.cnt}; }
inline void chkmax(data &x,data y) { if(x<y) x=y; }
inline data max(data x,data y) { return x<y?y:x; }

void dp(int x,int fad) {
	f[x][0]=f[x][1]=f[x][2]=nul;
	chkmax(f[x][2],tmp);
	for(pii p:to[x]) if(p.first!=fad) {
		int y=p.first, w=p.second;
		dp(y,x);
		chkmax(f[x][2],max(f[x][2]+f[y][0],f[x][1]+f[y][1]+w+tmp));
		chkmax(f[x][1],max(f[x][1]+f[y][0],f[x][0]+f[y][1]+w));
		chkmax(f[x][0],f[x][0]+f[y][0]);
	}
	chkmax(f[x][0],f[x][1]+tmp), chkmax(f[x][0],f[x][2]);
}

void check(int mid) {
	tmp=(data){-mid,1}, dp(1,0);
	Pluto=f[1][0].cnt;
}

signed main() {
	freopen("cms.in","r",stdin); 
	freopen("cms.out","w",stdout);
	n=read(), k=read()+1;
	up(i,2,n) {
		int u=read(), v=read(), w=read();
		to[u].pb(mp(v,w));
		to[v].pb(mp(u,w));
	}
	int l=-1e12, r=1e12;
	while(l<r) {
		int mid=(l+r)>>1;
		check(mid);
		if(Pluto==k) {
			cout << f[1][0].val+mid*k << '\n';
			return 0;
		}
		if(Pluto>k) l=mid+1;
		else r=mid;
	}
	check(l), cout << f[1][0].val+l*k << '\n';
	return 0;
}
posted @ 2025-10-22 16:15  Hypoxia571  阅读(11)  评论(0)    收藏  举报