Bronze

A Cow Gymnastics

题目:https://www.luogu.com.cn/problem/P5831

题解:用数组存一下出现位置,O(n^2)枚举一下就好。

代码:

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
#define I inline void
#define IN inline int
typedef long long ll;
I read(int &res){
re g=1;register char ch=getchar();res=0;
while(!isdigit(ch)){
if(ch=='-')g=-1;
ch=getchar();
}
while(isdigit(ch)){
res=(res<<3)+(res<<1)+(ch^48);
ch=getchar();
}
res*=g;
}
int n,m,a[100][100],b[100][100],sn,ans;
int main(){
freopen("gymnastics.in","r",stdin);
freopen("gymnastics.out","w",stdout);
read(m);read(n);
F(i,1,m){
F(j,1,n){
read(a[i][j]);
b[i][a[i][j]]=j;
}
}
F(i,1,n-1){
F(j,i+1,n){
sn=1;
if(b[1][i]>b[1][j]){
F(k,2,m)
if(b[k][i]<b[k][j]){
sn=0;
break;
}
}
else{
F(k,2,m){
if(b[k][i]>b[k][j]){
sn=0;
break;
}
}
}
ans+=sn;
}
}
cout<<ans;
return 0;
}

B Where Am I?

题目:https://www.luogu.com.cn/problem/P5832

题解:枚举一下K,哈希一下用map一存就行。复杂度:O(n^2)

代码:

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
#define I inline void
#define IN inline int
typedef long long ll;
I read(int &res){
re g=1;register char ch=getchar();res=0;
while(!isdigit(ch)){
if(ch=='-')g=-1;
ch=getchar();
}
while(isdigit(ch)){
res=(res<<3)+(res<<1)+(ch^48);
ch=getchar();
}
res*=g;
}
const int Mod=1e9+7,bas=131;
set<int>mp;
char c[110];
int n,m,a[110],j,s;
int main(){
freopen("whereami.in","r",stdin);
freopen("whereami.out","w",stdout);
read(n);
scanf("%s",c+1);
F(i,1,n){
a[i]=c[i]-'A'+1;
}
F(len,1,n){
mp.clear();m=1;
F(i,1,n-len+1){
j=i+len-1;s=0;
F(k,i,j){
s=(ll)s*bas%Mod;
s+=a[k];
}
if(mp.count(s)){
m=0;
break;
}
mp.insert(s);
}
if(m){
cout<<len;
return 0;
}
}
return 0;
}

C Livestock Lineup

题目:https://www.luogu.com.cn/problem/P5833

题解:按字典序爆搜即可。当然,我写的比较麻烦,

建了图,还要用每个点的度数分类讨论,其实复杂度

还是一样,O(8!*8)

代码:

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
#define I inline void
#define IN inline int
typedef long long ll;
I read(int &res){
re g=1;register char ch=getchar();res=0;
while(!isdigit(ch)){
if(ch=='-')g=-1;
ch=getchar();
}
while(isdigit(ch)){
res=(res<<3)+(res<<1)+(ch^48);
ch=getchar();
}
res*=g;
}
string s[9]={"0","Beatrice","Belinda","Bella","Bessie","Betsy","Blue","Buttercup","Sue"};
char c[100];
int n,m,a[10][10],x,y,du[10],ans[10],v[10];
I D_1(int x){
/* cout<<x<<" ";
F(i,1,x){
cout<<ans[i]<<" ";
}
cout<<endl;*/
if(x==9){
if(du[ans[x-1]]==2)return;
F(i,1,8){
cout<<s[ans[i]]<<endl;
}
exit(0);
}
re sn=0;
if(du[ans[x-1]]>=1){
F(i,1,8){
if(a[ans[x-1]][i]&&!v[i]){
sn++;
}
}
if(sn==2)return;
sn=1;
F(i,1,8){
if(a[ans[x-1]][i]&&!v[i]){
ans[x]=i,v[i]=1,D_1(x+1),v[i]=0;sn=0;
break;
}
}
if(!sn)return;
}
F(i,1,8){
if(v[i])continue;
ans[x]=i,v[i]=1,D_1(x+1);
ans[x]=0;v[i]=0;
}
}
int main(){
freopen("lineup.in","r",stdin);
freopen("lineup.out","w",stdout);
read(n);
memset(a,0,sizeof(a));
memset(du,0,sizeof(du));
F(i,1,n){
cin>>c+1;
m=strlen(c+1);
if(m==3)x=8;
if(m==4)x=6;
if(m==6)x=4;
if(m==7)x=2;
if(m==8)x=1;
if(m==9)x=7;
if(m==5){
if(c[3]=='l')x=3;
else x=5;
}
cin>>c+1>>c+1>>c+1>>c+1>>c+1;
m=strlen(c+1);
if(m==3)y=8;
if(m==4)y=6;
if(m==6)y=4;
if(m==7)y=2;
if(m==8)y=1;
if(m==9)y=7;
if(m==5){
if(c[3]=='l')y=3;
else y=5;
}
du[x]++;du[y]++;
a[x][y]=1;a[y][x]=1;
//cout<<x<<" "<<y<<endl;
}
F(i,1,n){
if(du[i]<2){
ans[1]=i;v[i]=1;
D_1(2);v[i]=0;
}
}
//cout<<"!";
return 0;
}

Silver

A MooBuzz

题目:https://www.luogu.com.cn/problem/P5834

题解:可以明显看出,每15次,有8个数被报出来。

随便写写就过了

复杂度O(1)

代码:

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
#define I inline void
#define IN inline int
typedef long long ll;
I read(int &res){
re g=1;register char ch=getchar();res=0;
while(!isdigit(ch)){
if(ch=='-')g=-1;
ch=getchar();
}
while(isdigit(ch)){
res=(res<<3)+(res<<1)+(ch^48);
ch=getchar();
}
res*=g;
}
int n,m,ans;
int main(){
freopen("moobuzz.in","r",stdin);
freopen("moobuzz.out","w",stdout);
read(n);
if(n%8==0){
ans=(n/8)*15;
ans--;
cout<<ans;
return 0;
}
ans=(n/8)*15;
n%=8;m=0;
F(i,1,n){
while(m%3==0||m%5==0)m++;
if(i==n){
ans+=m;
break;
}
m++;
}
cout<<ans;
return 0;
}

B Meetings

题目:https://www.luogu.com.cn/problem/P5835

题解:相信这道题的两个套路大家应该都见过:

1.不管这些牛怎么走,他们的相对位置都是不变的(没见过的一定要细细斟酌)

2.两头牛相遇后,可以看做是“擦肩而过”,也就是并没有改变方向。所以,

我们可以直接算出每头牛走到终点的时间。

知道了这两个性质,做法就顺水推舟了:

1.用类似归并排序的方法算出时刻T,由性质1,我们对时间和重量做出贡献的并不是一头牛(一定要小心);

2.因为时间已经确定,所以可以固定向一个方向走的牛不动,相当于另一个方向走的牛走了2*T个单位距离。

对两种方向的牛分别排序,双指针扫一下即可。具体实现看代码。

复杂度:O(nlogn)

代码:

#include<bits/stdc++.h>
using namespace std;
#define re register ll
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
#define I inline void
#define IN inline ll
typedef long long ll;
I read(ll &res){
re g=1;register char ch=getchar();res=0;
while(!isdigit(ch)){
if(ch=='-')g=-1;
ch=getchar();
}
while(isdigit(ch)){
res=(res<<3)+(res<<1)+(ch^48);
ch=getchar();
}
res*=g;
}
struct P{
ll x,w;
}l[50500],r[50500],p[101000];
ll n,m,num,tot,sum,W,X,d,Y,cnt,T,ans,L,R;
inline bool bb1(P a,P b){
return a.x==b.x?a.w>b.w:a.x>b.x;
}
inline bool bb2(P a,P b){
return a.x==b.x?a.w<b.w:a.x<b.x;
}
IN max(ll x,ll y){
return x>y?x:y;
}
int main(){
freopen("meetings.in","r",stdin);
freopen("meetings.out","w",stdout);
read(n);read(m);
tot=sum=num=0;
F(i,1,n){
read(W);read(X);read(d);num+=W;
p[i].x=X;p[i].w=W;
if(d==1)tot++,l[tot].x=X,l[tot].w=W;
else sum++,r[sum].x=X,r[sum].w=W;
}
sort(l+1,l+1+tot,bb1);
sort(r+1,r+1+sum,bb2);
sort(p+1,p+1+n,bb2);
X=1;Y=1;cnt=0;T=0;L=1;R=n;
while(cnt*2<num){
if(m-l[X].x>r[Y].x)cnt+=p[L++].w,T=r[Y].x,Y++;
else cnt+=p[R--].w,T=m-l[X].x,X++;
}
//cout<<X<<" "<<Y<<" "<<T<<endl;
sort(l+1,l+1+tot,bb2);
X=1;Y=1;
F(i,1,sum){
while(X<=tot&&l[X].x<max(0ll,r[i].x-T-T))X++;
while(Y<=tot&&l[Y].x<=r[i].x)Y++;
//cout<<X<<" "<<Y<<endl;
ans+=(Y-X);
}
cout<<ans;
return 0;
}

C Milk Visits

题目:https://www.luogu.com.cn/problem/P5836

题解:树剖+线段树板子题。详细讲解请见下一道Milk Visits。

复杂度:O(nlog^2n)

代码:

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
#define I inline void
#define IN inline int
typedef long long ll;
I read(int &res){
re g=1;register char ch=getchar();res=0;
while(!isdigit(ch)){
if(ch=='-')g=-1;
ch=getchar();
}
while(isdigit(ch)){
res=(res<<3)+(res<<1)+(ch^48);
ch=getchar();
}
res*=g;
}
char c[101000];
struct E{
int to,nt;
}e[202000];
#define T e[k].to
char sit;
int n,m,head[101000],fa[101000],X,Y,tot=-1,tr[101000],t[101000],siz[101000],top[101000],son[101000],id[101000],dep[101000];
I D_1(int x,int fat,int depth){
siz[x]=1;dep[x]=depth;son[x]=-1;fa[x]=fat;
re maxi=-1;
for(re k=head[x];k!=-1;k=e[k].nt){
if(T==fat)continue;
D_1(T,x,depth+1);
siz[x]+=siz[T];
if(maxi<siz[T])maxi=siz[T],son[x]=T;
}
}
IN lbt(int x){
return x&(-x);
}
I modi(int x){
while(x<=n)tr[x]++,x+=lbt(x);
}
I modify(int x){
while(x<=n)t[x]++,x+=lbt(x);
}
I D_2(int x,int fat,int topi){
top[x]=topi;id[x]=++tot;
if(c[x]=='H')modi(id[x]);else modify(id[x]);
if(son[x]!=-1)D_2(son[x],x,topi);
for(re k=head[x];k!=-1;k=e[k].nt){
if(T==fat||T==son[x])continue;
D_2(T,x,T);
}
}
IN ques_sum(int x){
re res=0;
while(x)res+=tr[x],x-=lbt(x);
return res;
}
IN query(int x){
re res=0;
while(x)res+=t[x],x-=lbt(x);
return res;
}
IN ques(int x,int y,char S){
re res=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
if(S=='H')res=(ques_sum(id[x])-ques_sum(id[top[x]]-1));
else res=(query(id[x])-query(id[top[x]]-1));
if(res)return 1;
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
if(S=='H')res=ques_sum(id[y])-ques_sum(id[x]-1);
else res=query(id[y])-query(id[x]-1);
if(res)return 1;
return 0;
}
int main(){
freopen("milkvisits.in","r",stdin);
freopen("milkvisits.out","w",stdout);
read(n);read(m);
cin>>c+1;
memset(head,-1,sizeof(head));
tot=-1;
F(i,1,n-1){
read(X);read(Y);
e[++tot].to=Y;
e[tot].nt=head[X];
head[X]=tot;
e[++tot].to=X;
e[tot].nt=head[Y];
head[Y]=tot;
}
D_1(1,0,1);
tot=0;
D_2(1,0,1);
while(m--){
read(X);read(Y);cin>>sit;
cout<<ques(X,Y,sit);
}
return 0;
}

Gold

A Milk Pumping

题目:https://www.luogu.com.cn/problem/P5837

题解:从1到1000枚举这个最小流量,跑最短路就好。

复杂度:O(1000*(n+m)logn)

代码:

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
#define I inline void
#define IN inline int
typedef long long ll;
I read(int &res){
re g=1;register char ch=getchar();res=0;
while(!isdigit(ch)){
if(ch=='-')g=-1;
ch=getchar();
}
while(isdigit(ch)){
res=(res<<3)+(res<<1)+(ch^48);
ch=getchar();
}
res*=g;
}
struct E{
int to,nt,w,v;
}e[2020];
#define T e[k].to
const int INF=1e9+7;
int n,m,head[1010],X,Y,W,V,dis[1010],vis[1010],p,ans,tot;
queue<int>q;
int main(){
freopen("pump.in","r",stdin);
freopen("pump.out","w",stdout);
read(n);read(m);
memset(head,-1,sizeof(head));tot=-1;
F(i,1,m){
read(X);read(Y);read(W);read(V);
e[++tot].to=Y;
e[tot].nt=head[X];
head[X]=tot;
e[tot].w=W;
e[tot].v=V;
e[++tot].to=X;
e[tot].nt=head[Y];
head[Y]=tot;
e[tot].w=W;
e[tot].v=V;
}
ans=0;
F(val,1,1000){
F(i,1,n)dis[i]=INF,vis[i]=0;
dis[1]=0,vis[1]=1;
q.push(1);
while(!q.empty()){
p=q.front();q.pop();vis[p]=0;
for(re k=head[p];k!=-1;k=e[k].nt){
if(e[k].v<val)continue;
if(dis[p]+e[k].w<dis[T]){
dis[T]=dis[p]+e[k].w;
if(!vis[T]){
vis[T]=1;
q.push(T);
}
}
}
}
if(dis[n]!=INF)ans=max(ans,val*1000000/dis[n]);
}
cout<<ans;
return 0;
}

B Milk Visits

题目:https://www.luogu.com.cn/problem/P5838

题解:在上一道Milk Visits中,我们用两个线段树维护了树上的信息,

这里,我们显然不能直接开1e5棵线段树,所以考虑避免这个问题。

Approach 1:可持久化线段树

这个嘛。。。不会的打一下模板题就会了,这里就不讲了。

Approach 2:离线

遇到不强制在线,且无修改的题目,离线算法是一定要take into consideration的。

我们将每个点的点权当做修改,和查询中每个人的喜好牛奶一起排序,按点权排序。

这样,我们就只需要在一棵线段树上进行修改、查询操作了。每次先打个lazytag清空

之前的信息,然后将一个点权的所有点插入线段树,然后查询。

具体实现还是看代码。

复杂度:O(nlog^2n)

代码:

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
#define I inline void
#define IN inline int
typedef long long ll;
I read(int &res){
re g=1;register char ch=getchar();res=0;
while(!isdigit(ch)){
if(ch=='-')g=-1;
ch=getchar();
}
while(isdigit(ch)){
res=(res<<3)+(res<<1)+(ch^48);
ch=getchar();
}
res*=g;
}
char c[101000];
struct E{
int to,nt;
}e[202000];
struct Q{
int x,y,p,id;
friend bool operator < (Q a,Q b){
return a.p==b.p?a.id<b.id:a.p<b.p;
}
}q[202000];
#define T e[k].to
char sit;
int n,m,now,ans[101000],a[100100],tr[404000],laz[404000],head[101000],fa[101000],X,Y,tot=-1,siz[101000],top[101000],son[101000],id[101000],dep[101000];
I D_1(int x,int fat,int depth){
siz[x]=1;dep[x]=depth;son[x]=-1;fa[x]=fat;
re maxi=-1;
for(re k=head[x];k!=-1;k=e[k].nt){
if(T==fat)continue;
D_1(T,x,depth+1);
siz[x]+=siz[T];
if(maxi<siz[T])maxi=siz[T],son[x]=T;
}
}
I D_2(int x,int fat,int topi){
top[x]=topi;id[x]=++tot;
q[tot].x=x;q[tot].y=id[x];q[tot].p=a[x];q[tot].id=-1;
//将每个点看做修改,id为负是为了使其排序时排在查询前面
if(son[x]!=-1)D_2(son[x],x,topi);
for(re k=head[x];k!=-1;k=e[k].nt){
if(T==fat||T==son[x])continue;
D_2(T,x,T);
}
}
#define all 1,1,n
#define lt k<<1,l,mid
#define rt k<<1|1,mid+1,r
I modi(int k,int l,int r,int x){
if(l==r){
tr[k]=1;
return;
}
if(laz[k])tr[k<<1]=tr[k<<1|1]=laz[k]=0,laz[k<<1]=laz[k<<1|1]=1;
re mid=(l+r)>>1;
if(x<=mid)modi(lt,x);
else modi(rt,x);
tr[k]=tr[k<<1]|tr[k<<1|1];
}
IN ques_sum(int k,int l,int r,int x,int y){
if(x>r||y<l)return 0;
if(x<=l&&r<=y)return tr[k];
if(laz[k])tr[k<<1]=tr[k<<1|1]=laz[k]=0,laz[k<<1]=laz[k<<1|1]=1;
re mid=(l+r)>>1;
return ques_sum(lt,x,y)|ques_sum(rt,x,y);
}
IN ques(int x,int y){
re res=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
res|=ques_sum(all,id[top[x]],id[x]);
if(res)return 1;
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
res|=ques_sum(all,id[x],id[y]);
if(res)return 1;
return 0;
}
int main(){
freopen("milkvisits.in","r",stdin);
freopen("milkvisits.out","w",stdout);
read(n);read(m);
F(i,1,n){
read(a[i]);
}
memset(head,-1,sizeof(head));
tot=-1;
F(i,1,n-1){
read(X);read(Y);
e[++tot].to=Y;
e[tot].nt=head[X];
head[X]=tot;
e[++tot].to=X;
e[tot].nt=head[Y];
head[Y]=tot;
}
D_1(1,0,1);
tot=0;
D_2(1,0,1);
F(i,1,m){
tot++;
read(q[tot].x);read(q[tot].y);read(q[tot].p);q[tot].id=i;
}
sort(q+1,q+1+tot);
now=q[1].p;
F(i,1,tot){
if(q[i].p>now)laz[1]=1,tr[1]=0,now=q[i].p;//点权变化时,清空线段树,打懒标记是一个不错的处理方式
if(q[i].id<0)modi(all,q[i].y);
else ans[q[i].id]=ques(q[i].x,q[i].y);
}
F(i,1,m){
cout<<ans[i];
}
return 0;
}

C Moortal Cowmbat

题目:https://www.luogu.com.cn/problem/P5839

题解:首先观察到m很小,先O(m^3)floyd判一下两两之间的最小代价。

设f[i][j]表示处理了前i个字符,最后一堆字符为j的最小代价。

可以口胡一下转移方程

暴力转移是O(n2m2)的,我们无法接受。

考虑优化这个dp。

O(n^2m)

考虑到当前的转移并不需要知道上一次的最后一段的字母是什么,我们

可以先对i的所有的f[i][j]取个min,再进行转移。

O(nm)

发现对于当前的i,可以转移到它的p是从1开始的一段连续区间。

我们设f[i]表示处理完前i个字母的最小代价,sum[i][j]表示从1到i,

将所有字母都变为j的代价。

这样,转移方程就可以写为:

f[i]=min{f[p]+sum[i][j]-sum[p][j},p \(\in\) [1,i-k]

枚举特定的j时,可以将sum[i][j]从这个max里提出来。

发现只需要取f[p]-sum[p][j]的min。

我们设mx[j]表示对于p \(\in\) [1,i-k],f[p]-sum[p][j]的最小值。

这样,转移就变成了O(1)。具体实现还有一些小细节,看代码吧~

复杂度:O(m^3+nm)

代码:

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
#define I inline void
#define IN inline int
typedef long long ll;
I read(int &res){
re g=1;register char ch=getchar();res=0;
while(!isdigit(ch)){
if(ch=='-')g=-1;
ch=getchar();
}
while(isdigit(ch)){
res=(res<<3)+(res<<1)+(ch^48);
ch=getchar();
}
res*=g;
}
const int INF=1e9+7;
char c[101000];
int n,m,k,a[101000],dis[30][30],mx[30],sum[101000][30],f[101000];
int main(){
freopen("cowmbat.in","r",stdin);
freopen("cowmbat.out","w",stdout);
read(n);read(m);read(k);
cin>>c+1;
F(i,1,n){
a[i]=c[i]-'a'+1;
}
F(i,1,m){
F(j,1,m){
read(dis[i][j]);
}
}
F(k,1,m){
F(i,1,m){
F(j,1,m){
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);//Floyd
}
}
}
memset(mx,0,sizeof(mx));
memset(sum,0,sizeof(sum));
F(i,1,k-1){
F(j,1,m){
sum[i][j]=sum[i-1][j]+dis[a[i]][j];//预处理sum
}
}
F(i,k,n){
f[i]=INF;
if(i>=(k<<1)){
F(j,1,m){
mx[j]=min(mx[j],f[i-k]-sum[i-k][j]);//i<2k时不存在合法的f
}
}
F(j,1,m){
sum[i][j]=sum[i-1][j]+dis[a[i]][j];
f[i]=min(f[i],mx[j]+sum[i][j]);
}
}
cout<<f[n];
return 0;
}

Platinum

A Greedy Pie Eaters

题目:http://www.usaco.org/index.php?page=viewproblem2&cpid=972

题目大意:有n个派,m头牛,每头牛有一个区间[l,r]和一个权值w。

没有两头牛有相同的[l,r]。

你需要选择一些牛,按一定顺序吃派。每头牛会吃完他的那个区间的所有派。

问在满足每头牛都至少有一个派吃的情况下,能获得的最大权值是多少。

n<=300,m<=45000

题解:n很小,可以想到区间DP。

设f[i][j]表示吃掉的派是[i,j]的子集的最大权值。

显然,f[i][j]=max{f[i][k-1]+f[k][j]},k\(\in\)[i,j]

但这样的转移不能加入新的牛。

可以考虑待合并的两个状态f[i][k-1]和f[k+1][j],此时k这个派还没有牛动。

我们设mx[k][i][j]表示满足i<=l[k]<=k<=r[k]<=j的所有牛的最大权值。

那么加入新牛的转移方程就出炉了:

f[i][j]=max{f[i][k-1]+mx[k][i][j]+f[k+1][j]},k\(\in\)(i,j)

复杂度O(n^3)

代码:

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
typedef long long ll;
#define I inline void
#define IN inline int
template<class D>I read(D &res){
res=0;register D g=1;register char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')g=-1;
ch=getchar();
}
while(isdigit(ch)){
res=(res<<3)+(res<<1)+(ch^48);
ch=getchar();
}
res*=g;
}
int n,m,mx[330][330][330],f[330][330],W,X,Y;
int main(){
freopen("pieaters.in","r",stdin);
freopen("pieaters.out","w",stdout);
read(n);read(m);
memset(mx,0,sizeof(mx));
F(i,1,m){
read(W);read(X);read(Y);
F(j,X,Y)mx[j][X][Y]=max(W,mx[j][X][Y]);
}
F(i,1,n){
FOR(j,i,1){
F(k,i,n){
if(j>1)mx[i][j-1][k]=max(mx[i][j-1][k],mx[i][j][k]);
if(k<n)mx[i][j][k+1]=max(mx[i][j][k+1],mx[i][j][k]);
}
}
}
FOR(i,n,1){
F(j,i,n){
F(k,i,j-1)f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]);
F(k,i,j)f[i][j]=max(f[i][j],mx[k][i][j]+(k>i?f[i][k-1]:0)+(k<j?f[k+1][j]:0));
}
}
printf("%d",f[1][n]);
return 0;
}

B Bessie's Snow Cow

题目:http://www.usaco.org/index.php?page=viewproblem2&cpid=973

题目大意:给你一棵树,要求支持两种操作:

1.给定x,c,给x的子树染上颜色c(一个节点可以有多个颜色)

2.给定x,求x的子树的所有节点的所有颜色个数和(每个节点单独算)

题解:这个题有两个难点:

1.修改时,如何更新其对子树内节点的贡献,以及如何上传对祖先的影响;

2.查询时,如何一次性统计子树内所有节点的贡献

我们发现,如果将一个操作的复杂度变为O(logn)甚至O(1),另一个操作的

复杂度将不可避免地到达O(n)。

考虑统计答案。答案可以分为两个部分:一是x或x的祖先已经染过的颜色,

这些的贡献可以一并计算;二是子树内染色的情况。

对于第一个,我们在每次修改时区间加就行了,当然还要撤销之前子树内

的一些修改操作的贡献。

我们以这棵树的dfs序为下标开一个树状数组,用差分维护每个节点已经染

上的颜色个数,再开1e5个set记录下每个颜色的染色情况,避免重复染色。

每次修改操作步骤如下:

1.判断x的祖先是否已经被染上c色。若已经染色,直接退出;

2.查询x子树内是否有节点染上c色。若已经染色,撤销其影响并在set中

删除此节点;

3.将此次修改加入set,进行区间修改。

那对于第二个,又该怎么求呢?

因为这些贡献是一段dfs序连续区间的单点贡献,我们可以另开一个树状数组

记录这个贡献。每次修改只需要单点+siz[x]即可。

修改操作的步骤同上。每次只需要查询[id[x]+1,id[x]+siz[x]-1]这段区间的

贡献即可(也就是x子树除去x节点的贡献)

设两个查询得到的值是ans1和ans2,那么答案即为:siz[x]*ans1+ans2

复杂度:因为每次修改只会被加入和撤销一次,每次都是O(logn),

查询也是O(logn)的,所以总复杂度即为O(nlogn)

代码:

#include<bits/stdc++.h>
using namespace std;
#define re register ll
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
typedef long long ll;
#define I inline void
#define IN inline ll
template<class D>I read(D &res){
res=0;register D g=1;register char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')g=-1;
ch=getchar();
}
while(isdigit(ch)){
res=(res<<3)+(res<<1)+(ch^48);
ch=getchar();
}
res*=g;
}
const ll INF=1e9+7;
struct E{
ll to,nt;
}e[202000];
#define T e[k].to
ll n,m,tot,sit,X,Y,head[101000],siz[101000],id[101000],p[101000],out[101000];
struct BIT{
ll tr[101000],res;
IN lbt(ll x){
return x&(-x);
}
I modi(ll x,ll w){while(x<=n){tr[x]+=w,x+=lbt(x);}}
IN ques(ll x){res=0;while(x){res+=tr[x],x-=lbt(x);}return res;}
}A,B;
set<ll>s[101000];
I modify(ll x,ll sn){
A.modi(id[x],sn);
A.modi(out[x]+1,-1*sn);
B.modi(id[x],sn*siz[x]);
//cout<<id[x]<<" "<<out[x]<<" "<<sn<<endl;
}
I D_1(ll x,ll fa){
id[x]=++tot;siz[x]=1;p[tot]=x;
for(re k=head[x];k!=-1;k=e[k].nt){
if(T==fa)continue;
D_1(T,x);siz[x]+=siz[T];
}
out[x]=tot;
}
int main(){
freopen("snowcow.in","r",stdin);
freopen("snowcow.out","w",stdout);
read(n);read(m);
memset(head,-1,sizeof(head));
tot=-1;
F(i,1,n-1){
read(X);read(Y);
e[++tot].to=Y;
e[tot].nt=head[X];
head[X]=tot;
e[++tot].to=X;
e[tot].nt=head[Y];
head[Y]=tot;
}
F(i,0,100000)s[i].insert(INF);
tot=0;
D_1(1,0);
//F(i,1,n)cout<<id[i]<<" "<<siz[i]<<" "<<out[i]<<endl;
while(m--){
read(sit);read(X);
if(sit==1){
read(Y);
auto P=s[Y].upper_bound(id[X]);
if(P!=s[Y].begin()&&out[p[*prev(P)]]>=out[X])continue;
while(1){
P=s[Y].upper_bound(id[X]);
if(*P>out[X])break;
modify(p[*P],-1);
s[Y].erase(P);
}
s[Y].insert(id[X]);
modify(X,1);
}
else printf("%lld\n",siz[X]*A.ques(id[X])+B.ques(out[X])-B.ques(id[X]));//printf("%d %d %d %d %d %lld\n",id[X],out[X],A.ques(id[X]),B.ques(out[X]),B.ques(id[X]),(ll)siz[X]*A.ques(id[X])+(ll)B.ques(out[X])-(ll)B.ques(id[X]));
}
return 0;
}

C Tree Depth

待填坑~

USACO19DEC题解的更多相关文章

  1. 【题解】[USACO19DEC]Milk Visits G

    题目戳我 \(\text{Solution:}\) 这题不要把思想局限到线段树上--这题大意就是求路径经过的值中\(x\)的出现性问题. 最开始的想法是值域线段树--看了题解发现直接\(vector\ ...

  2. 题解 P5837 【[USACO19DEC]Milk Pumping】

    这题其实想法挺简单的,因为他只需要简单的把每个点的花费和流量用dp记下来就好了 1.怎么记: 首先考虑dp的状态.由于所在的点和流量都要记,所以dp开二维,一维记所在的点,另一维记去哪 //dp[i] ...

  3. 题解 P5835 【 USACO19DEC Meetings S】

    前言 这道题目是道好题,想通了之后就可以把轻松这道题做出来. 正文 结论 先把一个结论写出来. 无论所有奶牛怎么走,它们的体重从左往右组成的序列是不会发生改变的. 这个结论简单地说明一下. 首先我们可 ...

  4. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  5. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  6. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  7. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

  8. 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解

    题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...

  9. 2016ACM青岛区域赛题解

    A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Jav ...

随机推荐

  1. 猎豹全球智库执行院长:中国App出海的三大规律和最具代表的五大垂直品类

    https://36kr.com/p/5100078 中国出海还是处于一个黄金时代. “国内互联网公司的竞争越来越白热化,出海的时间点变得越来越紧迫,”在36氪日前举办的“WISEx新出海行业峰会”上 ...

  2. 多项式的各类计算(多项式的逆/开根/对数/exp/带余除法/多点求值)

    预备知识:FFT/NTT 多项式的逆 给定一个多项式 F(x)F(x)F(x),请求出一个多项式 G(x)G(x)G(x),满足 F(x)∗G(x)≡1(mod xn)F(x)*G(x) \equiv ...

  3. EFK项目操作(待完善)

    Environment:{ 三台服务器均安装 kafka  zookeeper filebeat logstash kibana } 一.首先安装zookeeper,kafka,让机器有 leader ...

  4. shell脚本 mysql主从

    #!/bin/bash systemctl stop firewalld setenforce user="tom" password=" slave_ipaddr=&q ...

  5. (尚023)Vue_案例_交互添加

    最终达到效果: 1.做交互,首先需要确定操作哪个组件? 提交------操作组件Add.vue 2.从哪开始做起呢? 从绑定事件监听开始做起,确定你跟谁绑定事件监听,在回调函数中做什么, ====== ...

  6. 错误: 找不到或无法加载主类 Welcome.java

    问题原因: 不需要带.java

  7. centos6 启动docker报错

    1.启动docker报错: # service docker stop Stopping docker: [ OK ] [root@RSING data2]# service docker start ...

  8. rust所有权

    所有权与函数 fn main() { let s = String::from("hello"); takes_ownership(s); //s的值移动到函数里 let x = ...

  9. Scala函数柯里化(Currying or Curry)

    柯里化(Currying) 把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术. 简单的实现如下: scala> def ...

  10. 第06组 Beta冲刺(4/5)

    队名:拾光组 组长博客链接 作业博客链接 团队项目情况 燃尽图(组内共享) 组长:宋奕 过去两天完成了哪些任务 继续维护后端代码 继续学习深入python 继续研究匿名拨打电话问题.套牌多结果处理问题 ...