zoukankan      html  css  js  c++  java
  • 1.15 考试总结

    T1 ことりのおやつ(小鸟的点心)

    题目链接

    题意:给定一个无向有权图,通过一条边的时间为边权,每过去一单位时间,每一个点都会积累 (q) 毫米雪,初始雪厚 (h_{i}),雪积累到 (l_{i}) 以上就不能行走(起点,终点不算).求出 (s)(t) 的最短时间.

    有限制条件的最短路,只需在跑 (Dijkstra)(SPFA) 的时候稍微判断一下即可.

    #include <cstdio>
    #include <queue>
    #define inf (210000000000ll)
    typedef long long ll;
    inline ll rd(){
        ll x=0,p=1;
        char a=getchar();
        while((a<48||a>57)&&a!='-')a=getchar();
        if(a=='-')p=-p,a=getchar();
        while(a>47&&a<58)x=(x<<1)+(x<<3)+(a&15),a=getchar();
        return x*p;
    }
    inline ll min(ll x,ll y){return x<y?x:y;}
    const int N=100002,M=500002;
    struct Edge{
    	int to,next;ll w;
    }edge[M<<1];
    int head[N],cnt;
    int n,m,s,t;
    ll g,q;
    ll h[N],l[N];
    inline void add(int f,int t,ll w){
    	edge[++cnt].next=head[f];
    	edge[cnt].to=t;
    	edge[cnt].w=w;
    	head[f]=cnt;
    }
    ll dis[N];int vis[N];
    struct node{
    	int cur;ll dis;
    	node(int C=0,ll D=0){cur=C,dis=D;}
    	bool operator < (const node &y)const{
    		return y.dis<dis;
    	}
    };
    inline ll dijk(int s){
    	std::priority_queue<node> Q;
    	for(int i=1;i<=n;i++)dis[i]=inf;
    	dis[s]=0;
    	Q.push(node(s));
    	while(!Q.empty()){
    		int u=Q.top().cur;Q.pop();
    		if(vis[u]||h[u]+q*dis[u]>l[u])continue;
    		vis[u]=1;
    		for(int i=head[u];i;i=edge[i].next){
    			int v=edge[i].to;
    			if(dis[v]>dis[u]+edge[i].w)dis[v]=dis[u]+edge[i].w,Q.push(node(v,dis[v]));
    		}
    	}
    	return dis[t]<=g?dis[t]:-1;
    }
    int main(){
    	freopen("oyatsu.in","r",stdin);
    	freopen("oyatsu.out","w",stdout);
    	n=rd(),m=rd(),s=rd(),t=rd(),g=rd(),q=rd();
    	for(int i=1;i<=n;i++){
    		h[i]=rd(),l[i]=rd();
    		if(i==s||i==t)h[i]=-inf;
    	}
    	for(int i=1;i<=m;i++){
    		int u=rd(),v=rd();ll w=rd();
    		add(u,v,w),add(v,u,w);
    	}
    	ll ans=dijk(s);
    	if(ans>0)printf("%lld
    ",ans);
    	else puts("wtnap wa kotori no oyatsu desu!");
        return 0;
    }
    

    T2 教主的魔法

    题目链接

    题意:维护序列,支持区间加,查询区间大于等于一个数的个数.

    基础分块,每块维护一个单调的 (vector),边角暴力,块内二分.

    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <vector>
    #define rg register
    typedef long long ll;
    inline int rd(){
        int x=0,p=1;
        char a=getchar();
        while((a<48||a>57)&&a!='-')a=getchar();
        if(a=='-')p=-p,a=getchar();
        while(a>47&&a<58)x=(x<<1)+(x<<3)+(a&15),a=getchar();
        return x*p;
    }
    const int N=1000002,S=1002;
    int n,q,size,block;
    int bl[N],L[N],R[N],add[N],a[N];
    std::vector<int> v[S];
    inline void upd(int k){
    	v[k].clear();
    	for(rg int i=L[k];i<=R[k];i++)v[k].push_back(a[i]);
    	std::sort(v[k].begin(),v[k].end());
    }
    inline void update(int l,int r,int k){
    	if(bl[l]==bl[r]){
    		for(rg int i=l;i<=r;i++)a[i]+=k;
    		upd(bl[l]);
    		return;
    	}
    	for(rg int i=l;i<=R[bl[l]];i++)a[i]+=k;upd(bl[l]);
    	for(rg int i=L[bl[r]];i<=r;i++)a[i]+=k;upd(bl[r]);
    	for(rg int i=bl[l]+1;i<bl[r];i++)add[i]+=k;
    }
    inline int query(int l,int r,int k){
    	int ans=0;
    	if(bl[l]==bl[r]){
    		for(rg int i=l;i<=r;i++)ans+=(a[i]+add[bl[l]]<k);
    		return ans;
    	}
    	for(rg int i=l;i<=R[bl[l]];i++)ans+=(a[i]+add[bl[l]]<k);
    	for(rg int i=L[bl[r]];i<=r;i++)ans+=(a[i]+add[bl[r]]<k);
    	for(rg int i=bl[l]+1;i<bl[r];i++){
    		int val=k-add[i],x;
    		x=std::lower_bound(v[i].begin(),v[i].end(),val)-v[i].begin();
    		ans+=x;
    	}
    	return ans;
    }
    int main(){
    	freopen("magic.in","r",stdin);
    	freopen("magic.out","w",stdout);
    	n=rd(),q=rd();
    	size=sqrt(n),block=n/size+(n%size!=0);
    	for(rg int i=1;i<=block;i++)L[i]=(i-1)*size+1,R[i]=i*size;
    	R[block]=n;
    	for(rg int i=1;i<=n;i++)a[i]=rd(),bl[i]=(i-1)/size+1;
    	for(rg int i=1;i<=block;i++){
    		for(rg int j=L[i];j<=R[i];j++)v[i].push_back(a[j]);
    		std::sort(v[i].begin(),v[i].end());
    	}
    	while(q--){
    		char s[3];int l,r,k;
    		scanf("%s",s);
    		l=rd(),r=rd(),k=rd();
    		if(s[0]=='M')update(l,r,k);
    		else printf("%d
    ",r-l+1-query(l,r,k));
    	}
        return 0;
    }
    

    可能要吸氧气才能过

    T3 [BJOI2018]求和

    题目链接

    题意:给定一棵树,多组询问,求两点之间所有点的深度的 (k) 次方和.

    可以推出:对于两个点,它们之间存在的深度是连续的一段(一个点是它们的 (LCA) )或两段(两点中没有点是它们的 (LCA) ).故可以预处理 (i^{k}) 的前缀和,使用倍增求 (LCA) 就可以了.

    #include <cstdio>
    typedef long long ll;
    inline int rd(){
        int x=0,p=1;
        char a=getchar();
        while((a<48||a>57)&&a!='-')a=getchar();
        if(a=='-')p=-p,a=getchar();
        while(a>47&&a<58)x=(x<<1)+(x<<3)+(a&15),a=getchar();
        return x*p;
    }
    inline void swap(int &x,int &y){
    	int t=x;
    	x=y,y=t;
    }
    const int N=300002;
    const ll mod=998244353;
    inline ll fpow(ll b,ll p){
    	ll ans=1,tmp=b;
    	while(p){
    		if(p&1)ans=ans*tmp%mod;
    		tmp=tmp*tmp%mod;
    		p>>=1;
    	}
    	return ans;
    }
    struct Edge{
    	int to,next;
    }edge[N<<1];
    int head[N],cnt;
    int n,q;
    int dep[N],f[N][22];
    ll x[N][52],s[N][52];
    inline void init(int n){
    	for(int i=1;i<=n;i++){
    		x[i][0]=1;
    		for(int j=1;j<=50;j++)x[i][j]=x[i][j-1]*i%mod;
    	}
    	for(int k=1;k<=50;k++)
    		for(int i=1;i<=n;i++)
    			s[i][k]=(s[i-1][k]+x[i][k])%mod;
    }
    inline ll query(int l,int r,int k){
    	if(l==0)l=1;
    	return (s[r][k]-s[l-1][k]+mod)%mod;
    }
    inline void add(int f,int t){
    	edge[++cnt].next=head[f];
    	edge[cnt].to=t;
    	head[f]=cnt;
    }
    inline void dfs(int u,int ft){
    	dep[u]=dep[ft]+1,f[u][0]=ft;
    	for(int i=head[u];i;i=edge[i].next){
    		int v=edge[i].to;
    		if(v==ft)continue;
    		dfs(v,u);
    	}
    }
    inline int lca(int u,int v){
    	if(dep[u]<dep[v])swap(u,v);
    	for(int i=20;i>=0;i--)
    		if(dep[f[u][i]]>=dep[v])u=f[u][i];
    	if(u==v)return u;
    	for(int i=20;i>=0;i--)
    		if(f[u][i]!=f[v][i])u=f[u][i],v=f[v][i];
    	return f[u][0];
    }
    int main(){
    	freopen("sum.in","r",stdin);
    	freopen("sum.out","w",stdout);
    	n=rd();
    	init(n);
    	for(int i=1;i<n;i++){
    		int u=rd(),v=rd();
    		add(u,v),add(v,u);
    	}
    	dep[0]=-1;
    	dfs(1,0);
    	for(int j=1;j<=20;j++)
    		for(int i=1;i<=n;i++)
    			f[i][j]=f[f[i][j-1]][j-1];
    	q=rd();
    	while(q--){
    		int u=rd(),v=rd(),k=rd();
    		int l=lca(u,v);ll ans;
    		if(dep[u]<dep[v])swap(u,v);
    		if(l==v)ans=query(dep[l],dep[u],k);
    		else ans=((query(dep[l],dep[u],k)+query(dep[l]+1,dep[v],k))%mod);
    		printf("%lld
    ",ans);
    	}
        return 0;
    }
    
  • 相关阅读:
    ZoomBar 设计
    旋转toast 自定义toast方向,支持多个方向的显示,自定义View
    NA
    ISCSI共享
    DFS序
    矩阵快速幂
    SOJ4389 川大贴吧水王 队列
    ST表学习总结
    HDU 5724 Chess(SG函数)
    2017 计蒜之道 初赛 第一场 A、B题
  • 原文地址:https://www.cnblogs.com/wsk1202/p/12198363.html
Copyright © 2011-2022 走看看