唉 不打比赛不知道自己多菜 (果断打铁) 这篇博客还是写的很晚了 去年 十一月份打的比赛 今年 四月份才写
一直在等重现 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
*/
其他的题反正我是做不动了 六题似乎稳银了 快点的话 可以金 (记不太清了) 四题快的好像就能银
这场被戏称树论场 因为基本和树以及图都分不开 另外数论 几乎没用(有也是巨难的那种)
贴在这里 希望今年可以取得好成绩 (谨记教训)