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;
}

猜你喜欢

转载自www.cnblogs.com/wsk1202/p/12198363.html