The 2019 ICPC Asia Shanghai Regional Contest 2019 上海区域赛

唉 不打比赛不知道自己多菜   (果断打铁)  这篇博客还是写的很晚了  去年 十一月份打的比赛 今年 四月份才写   

一直在等重现  https://ac.nowcoder.com/acm/contest/4370 牛客上面有  大家可以看下

题目也不难 主要是人菜  另外这场数论选手基本作废(我们队相当于两人打一人读题)

按照我认为的难度顺序讲一下: 

  • B题是签到题 hash或者 trie 都行  
  • K题是二进制枚举吧  (枚举点为 0 或者 1)  比较坑的是 现场赛的时候 我们写的是标程的两倍复杂度 然后T了。。 感觉很难受
  • H题是二分+贪心  比较常见的套路  关键是贪心的策略 每次选子树中最小的加到父亲结点上 可以康康代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+10;
int n,k;
ll maxw = 0,all = 0;
ll a[N],b[N],c[N];
int h[N],nex[N<<1],to[N<<1],cur;
int ans = 0;
bool flag;
void addedge(int u,int v){
	to[++cur] = v;nex[cur] = h[u];h[u] = cur;
}

void dfs2(int u,int fa,ll mid){
	if(!flag) return;
	c[u]=a[u];
	vector<ll>S;
	for(int i = h[u]; i; i = nex[i]){
		int v = to[i];
		if(v==fa)continue;
		dfs2(v,u,mid);
		c[u]+=c[v];
		S.push_back(c[v]);
	}
	sort(S.begin(),S.end());
	while(c[u]>mid){
		//printf("c[u]=%lld\n",c[u]);
		ans++;
		c[u]-=*(S.end()-1);
		S.pop_back();
	}
	if(ans>k) {
		flag=false;
		return;
	}
}
bool check(ll val){
	flag=true,ans = 1;
	dfs2(1,0,val);
	//printf("val = %lld ans = %d\n",val,ans);
	return flag;
}
int main(){
	int t;
	scanf("%d",&t);
	int ct = 0; 
	while(t--){
		cur = 0;
		maxw = all = 0;
		scanf("%d%d",&n,&k);
		for(int i = 1; i <= n; i++) h[i] = 0;
		for(int i = 2; i <= n; i++){
			int u,v;
			scanf("%d%d",&u,&v);
			addedge(u,v);
			addedge(v,u);
		}
		for(int i = 1; i <= n; i++) scanf("%lld",&a[i]),all+=a[i],maxw = max(maxw,a[i]);
		ll L = maxw,R = all;
		ll lastans;
		while(L<=R){
			ll mid = L+R>>1;
			//printf("L=%lld R=%lld ",L,R);
			if(check(mid)) lastans = mid,R=mid-1;
			else L = mid+1; 
		}
		printf("Case #%d: %lld\n",++ct,lastans);	
	}
	return 0;
} 
/*
2 
9 7
1 1 1 2 1 3 5 2 
2 3 5 8 10 6 6 4 9 

*/
  • D题是个思维题把  反正我不会
  • E题最大生成树  似乎要用 基数排序 优化 kruskal
  • F题树链剖分+线段树裸题  。。。 难在哪呢 基本没什么要思路的  就是看你码力如何了  有些童鞋可能不会维护区间幂次方和  可以先做做 HDU 4578 
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
typedef long long ll;
const ll mod = 1e9+7; 
int nex[N<<1],h[N],to[N<<1],cur;
int siz[N],dep[N],rnk[N],tid[N],fa[N],top[N],son[N],cnt;
ll w[N];
#define lson (id<<1)
#define rson (id<<1|1)
struct node{
	int l,r;
	ll w,w2,w3,mul,add;
}a[N<<2]; 
void add_edge(int u,int v){
	to[++cur] = v;nex[cur] = h[u];h[u] = cur; 
}
void dfs1(int u){
	siz[u] = 1;
	for(int j = h[u]; j; j = nex[j]){
		int v = to[j];
		if(!dep[v]){
			dep[v] = dep[u]+1;
			fa[v] = u;
			dfs1(v);
			if(siz[v]>siz[son[u]]) son[u] = v;
			siz[u]+=siz[v];
		}
	}
}
void dfs2(int u,int t){
	top[u] = t;tid[u] = ++cnt;rnk[cnt] = u;
	if(son[u]) dfs2(son[u],t);
	for(int j = h[u]; j; j = nex[j]){
		int v = to[j];
		//printf("u = %d v = %d\n",u,v);
		if(v == fa[u] || v == son[u]) continue;
		dfs2(v,v);
	}
}
void pushup(int id){
	a[id].w = (a[lson].w + a[rson].w)%mod;
	a[id].w2 = (a[lson].w2 + a[rson].w2)%mod;
	a[id].w3 = (a[lson].w3 + a[rson].w3)%mod;
}
void build(int id,int l,int r){
	a[id].l = l;a[id].r = r;
	a[id].mul = 1LL;
	a[id].add = a[id].w  = a[id].w2 = a[id].w3 = 0LL;
	if(l == r){
		a[id].w = w[rnk[l]];
		a[id].w2 = a[id].w*a[id].w%mod;
		a[id].w3 = a[id].w2*a[id].w%mod;
		return;
	}int mid = l+r>>1;
	build(lson,l,mid);build(rson,mid+1,r);
	pushup(id);
}
void cal(int id,ll x,ll y){
	ll len = 1LL*(a[id].r-a[id].l+1);
	a[id].w3 = ((((x*x)%mod)*x%mod)*a[id].w3%mod+(((y*y)%mod)*y%mod)*len%mod+(((3LL*x*x)%mod)*a[id].w2%mod)*y%mod+(((3LL*y*y)%mod)*x%mod)*a[id].w%mod)%mod;
	a[id].w2 = (((x*x)%mod*a[id].w2)%mod+((2LL*x*y)%mod*a[id].w)%mod+((y*y)%mod*len)%mod)%mod;
	a[id].w = (x*a[id].w%mod+(y*len)%mod)%mod;
	a[id].mul = a[id].mul*x%mod;
	a[id].add = (a[id].add*x%mod+y)%mod;
}
void pushdown(int id){
	if(a[id].mul!=1LL||a[id].add){
		cal(lson,a[id].mul,a[id].add);
		cal(rson,a[id].mul,a[id].add);
		a[id].mul = 1LL;a[id].add = 0;
	}
}
void update(int id,int L,int R,ll x,ll y){
	if(L<=a[id].l&&R>=a[id].r){
		cal(id,x,y);
		return;
	}int mid = a[id].l+a[id].r>>1;
	pushdown(id);
	if(L<=mid) update(lson,L,R,x,y);
	if(R>mid) update(rson,L,R,x,y);
	pushup(id); 
}
ll query(int id,int L,int R){
	if(L<=a[id].l&&R>=a[id].r) return a[id].w3;
	int mid = a[id].l+a[id].r>>1;
	ll ans = 0;
	pushdown(id);
	if(L<=mid) ans+=query(lson,L,R);
	ans%=mod;
	if(R>mid) ans+=query(rson,L,R);
	ans%=mod;
	return ans;
}
void updatetree(int u,int v,ll x,ll y){
	while(top[u]!=top[v]){
		if(dep[top[u]]<dep[top[v]]) swap(u,v);
		update(1,tid[top[u]],tid[u],x,y),u = fa[top[u]];
	}
	if(dep[u]<dep[v]) swap(u,v);
	update(1,tid[v],tid[u],x,y);
}
ll querysum(int u,int v){
	ll ans = 0;
	while(top[u]!=top[v]){
		if(dep[top[u]]<dep[top[v]]) swap(u,v);
		ans=(ans+query(1,tid[top[u]],tid[u]))%mod,u = fa[top[u]];
	}
	if(dep[u]<dep[v]) swap(u,v);
	ans=(query(1,tid[v],tid[u])+ans)%mod;
	return ans;
}
int main(){
	int t;
	scanf("%d",&t);
	int ca=0;
	while(t--){
		int n;
		scanf("%d",&n);
		cur = cnt = 0;
		for(int i = 1; i <= n; i++) h[i] = 0;
		for(int i = 1; i <= n-1; i++){
			int u,v;
			scanf("%d%d",&u,&v);
			add_edge(u,v);
			add_edge(v,u);
		}
		for(int i = 1; i <= n; i++) 
		scanf("%lld",&w[i]),son[i] =dep[i] = 0;
		dep[1] = 1;
		dfs1(1);dfs2(1,1);
		build(1,1,n);
		int m;
		scanf("%d",&m);
		printf("Case #%d:\n",++ca);
		for(int i = 1; i <= m; i++){
			int op,u,v;
			ll val;
			scanf("%d%d%d",&op,&u,&v);
			if(op==4)
			printf("%lld\n",querysum(u,v));
			else {
				scanf("%lld",&val);
				if(op == 1) updatetree(u,v,0LL,val);
				else if(op == 2) updatetree(u,v,1LL,val);
				else updatetree(u,v,val,0LL);
			}
		}
	}
	return 0;
} 
/*
5
2 1
1 3
5 3
4 3
1 2 3 4 5
6
4 2 4
1 5 4 2
2 2 4 3
3 2 3 4
4 5 4
4 2 4
*/

其他的题反正我是做不动了  六题似乎稳银了  快点的话 可以金   (记不太清了)   四题快的好像就能银

这场被戏称树论场  因为基本和树以及图都分不开  另外数论 几乎没用(有也是巨难的那种)  

贴在这里  希望今年可以取得好成绩 (谨记教训)

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值