17.10.15

  • 上午
    • BZOJ 1036 [ZJOI2008]树的统计Count

      这是一个裸的 树链剖分+线段树

      代码:

      #include<cstdio>
      #include<cstring>
      #include<iostream>
      #define MAXN 30005
      #define INF 0x3f3f3f3f
      #define ls lson[u]
      #define rs rson[u]
      #define get(a,u,l,r,al,ar,kd); 
      if(kd==0) a=max(a,query(u,l,r,al,ar,kd));
      else a+=query(u,l,r,al,ar,kd);
      using namespace std;
      struct edge{
      	int to,next;
      }e[MAXN<<1];
      int lson[MAXN<<1],rson[MAXN<<1],mxn[MAXN<<1],sum[MAXN<<1];
      int head[MAXN],sze[MAXN],top[MAXN],val[MAXN],bs[MAXN],xl[MAXN],mp[MAXN],dep[MAXN],fa[MAXN];
      int n,m,ent=1,cnt,sz,rt;
      void add(int u,int v){
      	e[ent]=(edge){v,head[u]};
      	head[u]=ent++;
      }
      void find_heavy(int u,int f,int deep){
      	sze[u]=1; dep[u]=deep; fa[u]=f; int mxs=0;
      	for(int i=head[u];i;i=e[i].next){
      		int v=e[i].to;
      		if(v==fa[u]) continue;
      		find_heavy(v,u,deep+1);
      		sze[u]+=sze[v];
      		if(sze[v]>mxs) mxs=sze[v],bs[u]=v;
      	}
      }
      void connect_heavy(int u,int tp){
      	top[u]=tp; xl[++cnt]=u; mp[u]=cnt;
      	if(bs[u]) connect_heavy(bs[u],tp);
      	for(int i=head[u];i;i=e[i].next){
      		int v=e[i].to;
      		if(v==fa[u]||v==bs[u]) continue;
      		connect_heavy(v,v);
      	}
      }
      void pushup(int u){
      	mxn[u]=max((ls?mxn[ls]:-INF),(rs?mxn[rs]:-INF));
      	sum[u]=(ls?sum[ls]:0)+(rs?sum[rs]:0);
      }
      void build(int &u,int l,int r){
      	u=++sz;
      	if(l==r){
      		mxn[u]=sum[u]=val[xl[l]];
      		return ;
      	}
      	int mid=(l+r)>>1;
      	build(ls,l,mid);
      	build(rs,mid+1,r);
      	pushup(u);
      }
      void modify(int u,int l,int r,int p,int w){
      	if(l==r){
      		mxn[u]=sum[u]=w;
      		return;
      	}
      	int mid=(l+r)>>1;
      	if(p<=mid) modify(ls,l,mid,p,w);
      	else modify(rs,mid+1,r,p,w);
      	pushup(u);
      }
      void change(int a,int b){
      	int p=mp[a];
      	modify(rt,1,n,p,b);
      }
      int query(int u,int l,int r,int al,int ar,int kd){
      	if(al<=l&&r<=ar) return kd?sum[u]:mxn[u];
      	int mid=(l+r)>>1,now=kd?0:-INF;
      	if(al<=mid) {get(now,ls,l,mid,al,ar,kd);}
      	if(mid<ar) {get(now,rs,mid+1,r,al,ar,kd);}
      	return now;
      }
      void answer(int a,int b,int kd){
      	int ans=kd?0:-INF,l,r;
      	while(top[a]!=top[b]){
      		if(dep[top[a]]>dep[top[b]]) swap(a,b);
      		l=mp[top[b]]; r=mp[b];
      		if(l>r) swap(l,r);
      		get(ans,rt,1,n,l,r,kd);
      		b=fa[top[b]];
      	}
      	l=mp[a]; r=mp[b];
      	if(l>r) swap(l,r);
      	get(ans,rt,1,n,l,r,kd);
      	printf("%d
      ",ans);
      }
      int main(){
      	scanf("%d",&n);
      	for(int i=1,a,b;i<n;i++){
      		scanf("%d%d",&a,&b);
      		add(a,b); add(b,a);
      	}
      	for(int i=1;i<=n;i++) scanf("%d",&val[i]);
      	find_heavy(1,0,1);
      	connect_heavy(1,1);
      	build(rt,1,n);
      	scanf("%d",&m);
      	char com[10];
      	for(int i=1,a,b;i<=m;i++){
      		scanf(" %s %d%d",com,&a,&b);
      		if(com[1]=='H') change(a,b);
      		else if(com[1]=='M') answer(a,b,0);
      		else if(com[1]=='S') answer(a,b,1);
      	}
      	return 0;
      }
      
    • BZOJ 1037 [ZJOI2008]生日聚会Party

      DP神题
      dp[i][j][k][l]:放了i个人,有j个男的,
      且以i为结尾的所有区间中:男的最多比女的多k个,女的最多比男的多l个 的方案数

      代码: 

      #include<cstdio>
      #include<cstring>
      #include<iostream>
      using namespace std;
      const int mod=12345678;
      int dp[305][155][25][25];
      int n,m,p,ans; 
      int main(){
      	scanf("%d%d%d",&n,&m,&p);
      	dp[0][0][0][0]=1;
      	for(int i=0;i<n+m;i++)
      		for(int j=0;j<=n;j++)
      			for(int k=0;k<=p;k++)
      				for(int l=0;l<=p;l++){
      					if(j+1<=n&&k+1<=p)
      						dp[i+1][j+1][k+1][max(l-1,0)]=(dp[i+1][j+1][k+1][max(l-1,0)]+dp[i][j][k][l])%mod;
      					if(i-j+1<=m&&l+1<=p)
      						dp[i+1][j][max(k-1,0)][l+1]=(dp[i+1][j][max(k-1,0)][l+1]+dp[i][j][k][l])%mod;
      				}
      	for(int k=0;k<=p;k++)
      		for(int l=0;l<=p;l++)
      			ans=(ans+dp[n+m][n][k][l])%mod;
      	printf("%d",ans);
      	return 0;
      }
  • 晚上
原文地址:https://www.cnblogs.com/zj75211/p/7670034.html