• [NOIP2018模拟赛10.16]手残报告


    [NOIP2018模拟赛10.16]手残报告

    闲扯

    炉石乱斗模式美滋滋啊,又颓到好晚...

    上来T2先敲了树剖,看T1发现是个思博DP,然后没过大样例,写个暴力发现还是没过大样例!?才发现理解错题意了,真是太菜了

    然后看T3发现又要树剖,想了想发现边双缩点似乎能做...结果码来码去比赛临近结束才搞完,赶紧交代码.

    但是那台机子上的Chrome似乎是个假的,打开什么网页都巨慢,最后T1手残交了份一开始的错误代码上去,T2T3生死未卜

    结果40+0+0 T1错代码居然还有40?!数据这么水...再交遍正确代码一A

    T2T3下午检查的时候发现树剖犯了SB错误 还是记在了我错误笔记上的...太菜了

    下午改T3边双缩点居然A了std是圆方树的T3?!还跑了rank2?! (虽然现在xxzh巨佬是rank2

    而且第一发交的树剖还是有错的.这数据无力吐槽了

    晚上码T2,结果至今卡死在70 TLE三点,然而那台老年机都跑过了我也不知道咋回事

    T1 轻功

    分析

    思博DP,(f[i][j])表示当前使用第(j)轻功种走到(i)这个点的最短时间

    (f[i][j]=min(f[i-a[j]][p]+v[j]+[j!=p] imes w))

    预处理一下非法情况就好了

    代码

    /*
      code by RyeCatcher
    */
    inline char gc(){
        static char buf[SIZE],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,SIZE,stdin),p1==p2)?EOF:*p1++;
    }
    template <class T>inline void read(T &x){
        x=0;int ne=0;char c;
        while((c=gc())>'9'||c<'0')ne=c=='-';x=c-48;
        while((c=gc())>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48;x=ne?-x:x;return ;
    }
    const int maxn=505;
    const ll inf=1e17;
    int n,k,q;
    ll v[maxn];
    int a[maxn];
    bool fob[maxn][105];
    bool ok[maxn][105];
    ll w,f[maxn][105];
    namespace bf{
    	ll ans=inf;
    	void dfs(int now,int kk,ll c){
    		if(ok[now][kk])return ;
    		if(now>n)return ;
    		if(now==n){
    			ans=min(ans,c);
    			return ;
    		}
    		for(ri i=1;i<=k;i++){
    			if(ok[now+a[i]][i])continue;
    			if(i==kk){
    				dfs(now+a[i],i,c+v[i]);
    			}
    			else dfs(now+a[i],i,c+v[i]+w);
    		}
    		return ;
    	}
    	void main(){
    		for(ri i=1;i<=k;i++)dfs(0,i,0);
    		printf("%lld
    ",ans);
    		return ;
    	}
    }
    int main(){
    	int x,y;
    	FO(qinggong);
    	read(n),read(k),read(w);
    	for(ri i=1;i<=k;i++){
    		read(a[i]),read(v[i]);
    	}
    	memset(fob,0,sizeof(fob));
    	memset(ok,0,sizeof(ok));
    	read(q);
    	while(q--){
    		read(x),read(y);
    		fob[x][y]=1;
    	}
    	
    	for(ri i=0;i<=n;i++){
    		for(ri j=1;j<=k;j++)f[i][j]=inf;
    	}
    	int t=0;
    	for(ri i=0;i<=k;i++)if(!fob[0][i])f[0][i]=0;
    	for(ri i=0;i<=n;i++){
    		for(ri j=1;j<=k;j++){
    			bool flag=0;
    			if(i>=a[j]){
    				for(ri o=i-a[j];o<=i;o++)if(fob[o][j]){flag=1;break;}
    				if(flag)ok[i][j]=1;
    			}
    		}
    	}
    	if(n<=15){bf::main();return 0;}
    	for(ri i=1;i<=n;i++){
    		for(ri j=1;j<=k;j++){
    			if(ok[i][j])continue;
    			for(ri p=1;p<=k;p++){
    				if(i>=a[j]){
    					if(ok[i-a[j]][p])continue;
    					f[i][j]=min(f[i][j],1ll*(f[i-a[j]][p]+v[j]+((j==p)?0:w)));
    				}
    			}
    		}
    	}
    	ll ans=inf;
    	for(ri i=1;i<=k;i++)ans=min(ans,f[n][i]);
    	if(ans==inf)puts("-1");
    	else printf("%lld
    ",ans);
    	return 0;
    }
    
    

    T2 开荒

    精巧的树剖,询问时将所有点按(dfs)序排序

    钦定当前公共(LCA) (x),对于排序后第(i)个点和(i-1)号点的LCA (y),如果(y)(x)子树中,那么计算(i)(y)路径贡献(不包括(y)),否则根据DFS序排序后的性质, (y)就比(x)高明,将(y)设为公共(LCA),计算(fa[x])(i)号点路径贡献

    然后一直卡在70分。。。以后能用树状数组再也不用线段树了

    /*
      code by RyeCatcher
    */
    inline char gc(){
        static char buf[SIZE],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,SIZE,stdin),p1==p2)?EOF:*p1++;
    }
    #define gc getchar
    template <class T>inline void read(T &x){
        x=0;int ne=0;char c;
        while((c=gc())>'9'||c<'0')ne=c=='-';x=c-48;
        while((c=gc())>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48;x=ne?-x:x;return ;
    }
    const int maxn=200005;
    const int inf=0x7fffffff;
    int n,q;
    int que[10000005],cnt=0;
    struct Edge{
    	int ne,to;
    }edge[maxn<<1];
    int h[maxn],num_edge=1;
    inline void add_edge(int f,int to){
    	edge[++num_edge].ne=h[f];
    	edge[num_edge].to=to;
    	h[f]=num_edge;
    }
    ll w[maxn];
    int dep[maxn],fa[maxn],dfn[maxn],top[maxn],size[maxn],son[maxn],tot=0,rnk[maxn];
    void dfs_1(int now){
    	int v;
    	for(ri i=h[now];i;i=edge[i].ne){
    		v=edge[i].to;
    		if(v==fa[now]||dep[v])continue;
    		fa[v]=now,dep[v]=dep[now]+1;
    		dfs_1(v);
    		size[v]+=size[now];
    		if(!son[now]||size[v]>size[son[now]])son[now]=v;
    	}
    	return ;
    }
    void dfs_2(int now,int t){
    	int v;
    	top[now]=t,dfn[now]=++tot,rnk[tot]=now;
    	if(!son[now])return ;
    	dfs_2(son[now],t);
    	for(ri i=h[now];i;i=edge[i].ne){
    		v=edge[i].to;
    		if(v==fa[now]||v==son[now]||dfn[v])continue;
    		dfs_2(v,v);
    	}
    }
    int L,R,t;
    ll dta,ans=0;
    ll s[maxn<<2];
    inline void add(){for(;t<=n;t+=t&(-t))s[t]+=dta;}
    inline ll sum(int x){ll tmp=0;for(;x;x-=x&(-x))tmp+=s[x];return tmp;}
    inline ll calc(int l,int r) {return sum(r)-sum(l-1);}
    bool cmp(int a,int b){return dfn[a]<dfn[b];}
    inline int get_lca(int x,int y){
    	while(top[x]!=top[y]){
    		if(dep[top[x]]<dep[top[y]])std::swap(x,y);
    		x=fa[top[x]];
    	}
    	if(dep[x]>dep[y])return y;
    	return x;
    }
    inline void query_path(int x,int y){
    	while(top[x]!=top[y]){
    		if(dep[top[x]]<dep[top[y]])std::swap(x,y);
    		L=dfn[top[x]],R=dfn[x];
    		ans+=calc(L,R);
    		x=fa[top[x]];
    	}
    	if(dep[x]>dep[y])std::swap(x,y);
    	L=dfn[x],R=dfn[y];
    	ans+=calc(L,R);
    	return ;
    }
    inline void solve(){
    	int x,y;
    	if(cnt==1){
    		printf("%lld
    ",w[que[1]]);
    		return ;
    	}
    	x=que[1],ans=w[x];
    	for(ri i=2;i<=cnt;i++){
    		y=get_lca(que[i],que[i-1]);
    		if(dfn[x]<=dfn[y]){
    			query_path(y,que[i]);
    			ans-=w[y];
    		}
    		else{
    			query_path(fa[x],que[i]);
    			x=y;
    		}
    	}
    	printf("%lld
    ",ans);
    	return ;
    }
    int main(){
    	int x,y;
    	FO(kaihuang);
    	//freopen("ex_kaihuang.in","r",stdin);
    	read(n),read(q);
    	for(ri i=1;i<=n;i++)read(w[i]);
    	for(ri i=1;i<n;i++){
    		read(x),read(y);
    		add_edge(x,y);
    		add_edge(y,x);
    	}
    	dep[1]=1,fa[1]=0;
    	dfs_1(1);
    	dfs_2(1,1);
    	for(ri i=1;i<=n;i++){
    		t=dfn[i],dta=w[i];
    		add();
    	}
    	char opt[10];
    	while(q--){
    		scanf("%s",opt);
    		if(opt[0]=='Q'){
    			read(x);
    			cnt=0;
    			while(x){
    				que[++cnt]=x;
    				read(x);
    			}
    			if(cnt==0){
    				puts("0");
    				continue;
    			}
    			std::sort(que+1,que+1+cnt,cmp);
    			cnt=std::unique(que+1,que+1+cnt)-(que+1);
    			solve();
    		}
    		else{
    			read(x),read(y);
    			t=dfn[x],dta=y-w[x],w[x]=y;
    			add();
    		}
    		//puts("fafa");
    	}
    	return 0;
    }
    
    

    T3 跑商

    分析

    考场上Tarjan还有行写反了G

    标算圆方树不会啊,我这个边双感觉就是个挺靠谱的假算法,边双缩点后形成的的树进行树链剖分,缩的点用一个(multiset)动态维护点内的最小值,查询直接树剖

    代码

    inline char gc(){
        static char buf[SIZE],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,SIZE,stdin),p1==p2)?EOF:*p1++;
    }
    #define gc getchar
    template <class T>inline void read(T &x){
        x=0;int ne=0;char c;
        while((c=gc())>'9'||c<'0')ne=c=='-';x=c-48;
        while((c=gc())>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48;x=ne?-x:x;return ;
    }
    const int maxn=200005;
    const int inf=0x7fffffff;
    int n,m,q;
    ll w[maxn],val[maxn];
    struct Edge{
    	int ne,to;
    }edge[maxn<<1];
    struct SE{
    	int ne,to;
    }se[maxn<<1];
    int h[maxn],num_edge=1;
    inline void add_edge(int f,int to){
    	edge[++num_edge].ne=h[f];
    	edge[num_edge].to=to;
    	h[f]=num_edge;
    } 
    int sh[maxn],num_se=1;
    inline void add_se(int f,int to){
    	se[++num_se].ne=sh[f];
    	se[num_se].to=to;
    	sh[f]=num_se;
    }
    namespace Tree{//树的情况
    	int dep[maxn],fa[maxn],dfn[maxn],rnk[maxn],tot=0,top[maxn],son[maxn],size[maxn];
    	void dfs_1(int now){
        	int v;
        	size[now]=1;
        	for(ri i=h[now];i;i=edge[i].ne){
            	v=edge[i].to;
            	if(dep[v]||v==fa[now])continue;
            	dep[v]=dep[now]+1;
            	fa[v]=now;
            	dfs_1(v);
            	size[now]+=size[v];
            	if(!son[now]||size[son[now]]<size[v])son[now]=v;
        	}
    	}
    	void dfs_2(int now,int t){
        	int v;
        	top[now]=t;
        	dfn[now]=++tot,rnk[tot]=now;
        	if(!son[now])return ;
        	dfs_2(son[now],t);
        	for(ri i=h[now];i;i=edge[i].ne){
            	v=edge[i].to;
            	if(dfn[v]||v==fa[now]||v==son[now])continue;
            	dfs_2(v,v);
        	}
        	return ;
    	}
    	int L,R,t;
    	ll dta;
    	ll mi[maxn<<2];
    	inline void up(int now){mi[now]=min(mi[now<<1],mi[now<<1|1]);}
    	void build(int now,int l,int r){
        	if(l==r){
            	mi[now]=w[rnk[l]];//注意!!! 
            	return ;
        	}
        	int mid=(l+r)>>1;
        	build(now<<1,l,mid);
        	build(now<<1|1,mid+1,r);
        	up(now);
        	return ;
    	}
    	void update(int now,int l,int r){
        	if(l==r){
            	mi[now]=dta;
            	return ;
        	}
        	int mid=(l+r)>>1;
        	if(t<=mid)update(now<<1,l,mid);
        	else update(now<<1|1,mid+1,r);
        	up(now);
        	return ;
    	}
    	ll ans=inf;
    	void query(int now,int l,int r){
        	if(L<=l&&r<=R){
            	ans=min(ans,mi[now]);
            	return ;
        	}
        	int mid=(l+r)>>1;
        	if(L<=mid)query(now<<1,l,mid);
        	if(mid<R)query(now<<1|1,mid+1,r);
        	up(now);
        	return ;
    	}
    	inline void query_path(int x,int y){
        	ans=inf;
        	while(top[x]!=top[y]){
            	if(dep[top[x]]<dep[top[y]])std::swap(x,y);
            	L=dfn[top[x]],R=dfn[x];
            	query(1,1,n);
            	x=fa[top[x]];
        	}
        	if(dfn[x]>dfn[y])std::swap(x,y);
        	L=dfn[x],R=dfn[y];
        	query(1,1,n);
        	return ;
    	}
    	void main(){
    		int x,y;
    		dep[1]=1,fa[1]=1;
        	dfs_1(1);
        	dfs_2(1,1);
        	build(1,1,n);
        	char opt[5];
        	//puts("fafa");
        	read(q);
        	while(q--){
            	scanf("%s",opt);
           	 	if(opt[0]=='C'){
                	read(x),read(dta);
                	t=dfn[x];
                	w[x]=dta;
                	update(1,1,n);
            	}
            	else{
                	read(x),read(y);
                	ans=inf;
                	if(x==y)puts("0");
                	else {
    					query_path(x,y);
                		printf("%lld
    ",max(1ll*0,w[x]-ans));
                		//system("PAUSE");
                	}
            	}
        	}
    		return;
    	}
    }
    int inb[maxn],cnt=0;
    multiset <ll> mib[maxn];
    int dep[maxn],rnk[maxn],fa[maxn],dfn[maxn],tot=0,size[maxn],son[maxn],top[maxn];
    void dfs_1(int now){
    	int v;size[now]=1;
    	for(ri i=sh[now];i;i=se[i].ne){
    		v=se[i].to;
    		if(v==fa[now]||dep[v])continue;
    		dep[v]=dep[now]+1,fa[v]=now;
    		dfs_1(v);
    		size[now]+=size[v];
    		if(!son[now]||size[son[now]]<size[v])son[now]=v;
    	}
    	return ;
    }
    bool vis[maxn];
    void dfs_2(int now,int t){
    	int v;top[now]=t;
    	dfn[now]=++tot,rnk[tot]=now;
    	if(!son[now])return ;
    	dfs_2(son[now],t);
    	for(ri i=sh[now];i;i=se[i].ne){
    		v=se[i].to;
    		if(dfn[v]||v==son[now]||v==fa[now])continue;
    		dfs_2(v,v);
    	}
    	return ;
    }
    int L,R,t;
    ll lst,dta;
    ll mi[maxn<<2];
    inline void up(int now){mi[now]=min(mi[now<<1],mi[now<<1|1]);}
    void build(int now,int l,int r){
    	if(l==r){
    		mi[now]=*mib[rnk[l]].begin();
    		return ;
    	}
    	int mid=(l+r)>>1;
    	build(now<<1,l,mid);
    	build(now<<1|1,mid+1,r);
    	up(now);
    }
    void update(int now,int l,int r){
    	if(l==r){
    		mib[rnk[l]].erase(mib[rnk[l]].lower_bound(lst));
    		mib[rnk[l]].insert(dta);
    		mi[now]=*mib[rnk[l]].begin();
    		return ;
    	}
    	int mid=(l+r)>>1;
    	if(t<=mid)update(now<<1,l,mid);
    	else update(now<<1|1,mid+1,r);
    	up(now);
    	return ;
    }
    ll ans=inf;
    void query(int now,int l,int r){
    	if(L<=l&&r<=R){
    		ans=min(ans,mi[now]);
    		return ;
    	}
    	int mid=(l+r)>>1;
    	if(L<=mid)query(now<<1,l,mid);
    	if(mid<R)query(now<<1|1,mid+1,r);
    	up(now);
    	return ;
    }
    inline void query_path(int x,int y){
    	ans=inf;
    	while(top[x]!=top[y]){
    		if(dep[top[x]]<dep[top[y]])std::swap(x,y);
    		L=dfn[top[x]],R=dfn[x];
    		//printf("%d %d %d %d
    ",x,y,L,R);
    		query(1,1,cnt);
    		x=fa[top[x]];
    	}
    	if(dfn[x]>dfn[y])std::swap(x,y);
    	L=dfn[x],R=dfn[y];//puts("wtf");
    	//printf("%d %d %d %d
    ",x,y,L,R);
    	query(1,1,cnt);
    	return ;
    }
    int low[maxn],dd[maxn],pc=0;
    bool bri[maxn<<1];
    void tarjan(int now,int id){
    	int v;
    	dd[now]=low[now]=++pc;
    	for(ri i=h[now];i;i=edge[i].ne){
    		v=edge[i].to;
    		if(!dd[v]){
    			tarjan(v,i);
    			low[now]=min(low[now],low[v]);
    			if(dd[now]<low[v]){
    				bri[i]=bri[i^1]=1;
    			}
    		}
    		else if(i!=(id^1))low[now]=min(low[now],dd[v]);
    	}
    	return ;
    }
    void pre_dfs(int now,int fa){
    	int v;
    	vis[now]=1;
    	mib[cnt].insert(w[now]);
    	inb[now]=cnt;
    	//printf("%d %d
    ",now,fa);
    	for(ri i =h[now];i;i=edge[i].ne){
    		v=edge[i].to;
    		if(inb[v]||bri[i]||bri[i^1]||v==fa)continue;
    		pre_dfs(v,now);
    	}
    	return ;
    }
    bool fg=0;
    void pre_ck(int now,int fa){
    	int v;vis[now]=1;
    	for(ri i=h[now];i;i=edge[i].ne){
    		v=edge[i].to;
    		if(v==fa)continue;
    		if(vis[v]){fg=1;return ;}
    		pre_ck(v,now);
    	}
    	return ;
    }
    int main(){
    	int x,y;
    	FO(paoshang);
    	//freopen("paoshang1.in","r",stdin);
    	read(n),read(m);
    	for(ri i=1;i<=n;i++)read(w[i]);
    	for(ri i=1;i<=m;i++){
    		read(x),read(y);
    		add_edge(x,y);
    		add_edge(y,x);
    	}
    	pre_ck(1,0);
    	if(!fg){Tree::main();return 0;}
    	memset(vis,0,sizeof(vis));
    	for(ri i=1;i<=n;i++)if(!dd[i])tarjan(i,0);
    	for(ri i=1;i<=n;i++){
    		if(!inb[i]){
    			cnt++;
    			pre_dfs(i,0);
    		}
    	}
    	for(ri i=1;i<=n;i++){
    		x=inb[i];
    		for(ri j=h[i];j;j=edge[j].ne){
    			y=inb[edge[j].to];
    			if(x!=y){
    				add_se(x,y);
    				add_se(y,x);
    			}
    		}
    	}
    	//printf("--%d--
    ",cnt);	
    	dep[1]=1,fa[1]=0;
    	tot=0;
    	dfs_1(1);
    	dfs_2(1,1);
    	build(1,1,cnt);
    	read(q);
    	char opt[5];
    	while(q--){
    		scanf("%s",opt);
    		if(opt[0]=='C'){
    			read(x),read(dta);
    			lst=w[x];
    			t=dfn[inb[x]];
    			w[x]=dta;
    			update(1,1,cnt);
    		}
    		else{
    			read(x),read(y);
    			if(x==y)puts("0");
    			else {
    				query_path(inb[x],inb[y]);
    				printf("%lld
    ",max(1ll*0,w[x]-ans));
    			}		
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    Twitter注册
    iOS项目的完整重命名方法图文教程
    加载gif动态图的三种方式
    只 一行显示可左右滚动的文本(UITextField中文限制)
    iOS学习资料链接
    GCD常用方法
    移动端轮播完整版css3加原生写法
    zepto-touch.js插件
    移动端续讲及zepto移动端插件外加touch插件介绍
    解决ios和Android的差异
  • 原文地址:https://www.cnblogs.com/Rye-Catcher/p/9801492.html
Copyright © 2020-2023  润新知