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\n",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\n",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\n",ans);
	}
    return 0;
}
posted @ 2020-01-15 19:19  wsk1202  阅读(187)  评论(1编辑  收藏  举报