• 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;
        }
    • 晚上
  • 相关阅读:
    c++获取线程id
    一个基于c++的log库
    防止socket程序重启等待2MSL时间
    c++头文件循环引用
    Myeclipse 8.5 优化设置
    来道题 求解释
    MyEclipse常用设置笔记
    Ubuntu 学习笔记
    Linux 下常用命令
    Oracle 学习笔记 常用查询命令篇
  • 原文地址:https://www.cnblogs.com/zj75211/p/7670034.html
Copyright © 2020-2023  润新知