牛客练习赛 58——树链剖分

A - 牛能和宝石

签到题

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
using namespace std;
const int N=100010;
int a[N],b[N];
int n;
int main()
{
    
    
    IO;
    int T=1;
    //cin>>T;
    while(T--)
    {
    
    
        cin>>n;
        for(int i=1;i<=n;i++) cin>>a[i];
        for(int i=1;i<=n;i++) cin>>b[i];
        sort(a+1,a+1+n);
        sort(b+1,b+1+n);
        int res=0;
        for(int i=1;i<=n;i++) res=max(res,a[i]+b[n-i+1]);
        cout<<res<<'\n';
    }
    return 0;
    
}

B - 牛妹和01串

签到题

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
using namespace std;
const int N=100010;
int a[N],b[N];
int n;
int main()
{
    
    
    IO;
    int T=1;
    //cin>>T;
    while(T--)
    {
    
    
        string s;
        cin>>s;
        int res=0,cnt0=0,cnt1=0;
        for(auto t:s)
        {
    
    
            if(t=='1') cnt1++;
            if(t=='0') cnt0++;
            if(cnt0&&cnt1)
            {
    
    
                res++;
                cnt0=0;
                cnt1=0;
            }
        }
        cout<<res<<'\n';
    }
    return 0;
}

C - 矩阵消除游戏

m , n m,n m,n很小考虑直接枚举
行列都枚举会TLE,考虑优化:如果行确定那么选择列可以贪心。

TLE代码——枚举行列
//lajiTLE代码
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=20;
int a[N][N];
int n,m,k;
vector<int> state[N];
int lowbit(int x)
{
    
    
    return x&-x;
}
int calc(int x)
{
    
    
    int res=0;
    while(x)
    {
    
    
        x-=lowbit(x);
        res++;
    }
    return res;
}
ll solve(int r,int c)
{
    
    
    ll res=0;
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            if((r>>i&1)||(c>>j&1)) res+=a[i][j];
    return res;
}
int main()
{
    
    
    IO;
    int T=1;
    //cin>>T;
    while(T--)
    {
    
    
        cin>>n>>m>>k;
        for(int i=0;i<n;i++) 
            for(int j=0;j<m;j++) cin>>a[i][j];
            
        k=min(k,min(n,m));
        for(int i=0;i<1<<min(n,m);i++) state[calc(i)].push_back(i);
        ll res=0;
        for(int r=0;r<=k;r++)
        {
    
    
            int c=k-r;
            for(int i=0;i<state[r].size();i++)
            {
    
    
                int nowr=state[r][i];
                for(int j=0;j<state[c].size();j++)
                {
    
    
                    int nowc=state[c][j];
                    res=max(res,solve(nowr,nowc));
                }
            }
        }
        cout<<res<<'\n';
    }
    return 0;
    
}
AC代码——枚举行贪心列
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=20;
int a[N][N];
int n,m,k;
vector<int> state[N];
int lowbit(int x)
{
    
    
    return x&-x;
}
int calc(int x)
{
    
    
    int res=0;
    while(x)
    {
    
    
        x-=lowbit(x);
        res++;
    }
    return res;
}
int b[N];
ll solve(int row,int cnt)
{
    
    
    ll res=0;
    for(int j=0;j<m;j++)
    {
    
    
        b[j]=0;
        for(int i=0;i<n;i++)
        {
    
    
            if(row>>i&1) continue;
            b[j]+=a[i][j];
        }
    }
    sort(b,b+m);
    reverse(b,b+m);
    for(int i=0;i<n;i++)
        if(row>>i&1)
            for(int j=0;j<m;j++) res+=a[i][j];
    for(int i=0;i<cnt;i++)
        res+=b[i];
    return res;
}
int main()
{
    
    
    IO;
    int T=1;
    //cin>>T;
    while(T--)
    {
    
    
        cin>>n>>m>>k;
        for(int i=0;i<n;i++) 
            for(int j=0;j<m;j++) cin>>a[i][j];
            
        k=min(k,min(n,m));
        for(int i=0;i<1<<min(n,m);i++) state[calc(i)].push_back(i);
        ll res=0;
        for(int r=0;r<=k;r++)
        {
    
    
            int c=k-r;
            for(int i=0;i<state[r].size();i++)
            {
    
    
                
                int nowr=state[r][i];
                res=max(res,solve(nowr,c));
            }
        }
        cout<<res<<'\n';
    }
    return 0;
    
}

D - 迷宫

题解好像是dp做的,我dijkstra瞎搞出来了。
分析题目不难知道向上走和向左走没什么用,于是只考虑向右走和向下走

向右走的代价为0(不需要堵路)。
如果能向右走,那么如果在该点向下走那么就要花费1代价(堵路),否则向下走的代价为0。

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1010;
int g[N][N];
int n,m;
int dist[N][N];
bool st[N][N];
char s[N][N];
struct node
{
    
    
    int d,x,y;
    bool operator<(const node& o) const
    {
    
    
        return d>o.d;
    }
};
void bfs()
{
    
    
    memset(dist,0x3f,sizeof dist);
    memset(st,0,sizeof st);
    dist[1][1]=0;
    priority_queue<node> q;
    q.push({
    
    0,1,1});
    
    while(q.size())
    {
    
    
        int x=q.top().x,y=q.top().y;
        q.pop();
        if(st[x][y]) continue;
        st[x][y]=1;
        int a,b;
        int ok1=1,ok2=0;
        a=x,b=y+1;
        if(a<1||b<1||a>n||b>m||g[a][b]) ok1=0;
        else 
        {
    
    
            if(dist[a][b]>dist[x][y])
            {
    
    
                dist[a][b]=dist[x][y];
                q.push({
    
    dist[a][b],a,b});
            }
        }
        a=x+1,b=y;
        if(a<1||b<1||a>n||b>m||g[a][b]) ok2=0;
        else 
        {
    
    
            if(dist[a][b]>dist[x][y]+ok1)
            {
    
    
                dist[a][b]=dist[x][y]+ok1;
                q.push({
    
    dist[a][b],a,b});
            }
        }
        
    }
}
int main()
{
    
    
    IO;
    int T=1;
    //cin>>T;
    while(T--)
    {
    
    
        cin>>n>>m;
        for(int i=1;i<=n;i++) cin>>s[i]+1;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                g[i][j]=s[i][j]-'0';
        bfs();
        if(dist[n][m]==0x3f3f3f3f) cout<<-1<<'\n';
        else cout<<dist[n][m]<<'\n';
        
    }
    return 0;
    
}

E - 最大GCD

首先暴力把每个 a i a_i ai的约数搞出来,用一个vector存储一下, d [ i ] d[i] d[i]表示存在约数是 i i i a i a_i ai所在的位置下标。询问同样先把所有约数搞出来,然后逆序去vector<int> d[]二分查找看看是否在所给区间内即可。

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=100010;
int n,m;
vector<int> d[N];
int main()
{
    
    
    //IO;
    int T=1;
    //cin>>T;
    while(T--)
    {
    
    
        cin>>n>>m;
        for(int i=1;i<=n;i++)
        {
    
    
            int a;
            cin>>a;
            for(int j=1;j<=a/j;j++)
            {
    
    
                if(a%j) continue;
                d[j].push_back(i);
                if(j!=a/j) d[a/j].push_back(i);
            }
        }
        while(m--)
        {
    
    
            int l,r,x;
            cin>>l>>r>>x;
            vector<int> dx;
            for(int i=1;i<=x/i;i++)
            {
    
    
                if(x%i) continue;
                dx.push_back(i);
                if(i!=x/i) dx.push_back(x/i);
            }
            sort(dx.begin(),dx.end());
            reverse(dx.begin(),dx.end());
            for(auto t:dx)
            {
    
    
                if(!d[t].size()) continue;
                int lnow=lower_bound(d[t].begin(),d[t].end(),l)-d[t].begin();
                if(lnow>=d[t].size()) continue;
                if(d[t][lnow]<=r) 
                {
    
    
                    cout<<t<<'\n';
                    break;
                }
            }
            
        }
        
    }
    return 0;
    
}

F - XOR TREE

分析一下不难发现每个点对答案的贡献有以下规律:

  • 如果路径点数是奇数个点,那么等效于所有偶数次序的点被记录一次
  • 如果路径点数是偶数个点,那么所有点都被计入一次

①路径点数可以根据求树上路径距离间接求得
②对于一条路径上的奇偶点,可以根据端点的奇偶性+深度的奇偶性来确定。

因此树剖后根据dfs序建立两棵线段树分别维护深度是奇数和深度是偶数点的区间异或值。
查询和修改的时候只需要分类讨论以下即可。

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=200010;
//***************************************************************
int read()
{
    
    
    int x=0;
    char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=getchar();
    return x;
}
//***************************************************************
int n,q;
int w[N],a[N],b[N];
int h[N],e[2*N],ne[2*N],idx;
void add(int a,int b)
{
    
    
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}
int fa[N],dep[N],sz[N],son[N];
void dfs1(int u,int p)
{
    
    
    sz[u]=1;    
    fa[u]=p,dep[u]=dep[p]+1;
    for(int i=h[u];i!=-1;i=ne[i])
    {
    
    
        int j=e[i];
        if(j==p) continue;
        dfs1(j,u);
        sz[u]+=sz[j];
        if(sz[j]>sz[son[u]])
            son[u]=j;
    }
}
int timestamp,dfn[N],top[N];
void dfs2(int u,int t)
{
    
    
    dfn[u]=++timestamp;
    top[u]=t;
    if(!son[u]) return;
    dfs2(son[u],t);
    for(int i=h[u];i!=-1;i=ne[i])
    {
    
    
        int j=e[i];
        if(j==fa[u]||j==son[u]) continue;
        dfs2(j,j);
    }
}
int lca(int u,int v)
{
    
    
    while(top[u]!=top[v])
    {
    
    
        if(dep[top[u]]<dep[top[v]]) swap(u,v);
        u=fa[top[u]];
    }
    return dep[u]<dep[v]?u:v;
}
int dist(int u,int v)
{
    
    
    return dep[u]+dep[v]-2*dep[lca(u,v)];
}
struct node1
{
    
    
    struct node2
    {
    
    
        int l,r;
        int val;
    }tree[N<<2];
    void pushup(int u)
    {
    
    
        tree[u].val=tree[u<<1].val^tree[u<<1|1].val;
    }
    void build(int u,int l,int r,int w[])
    {
    
    
        tree[u]={
    
    l,r};
        if(l==r) 
        {
    
    
            tree[u].val=w[l];
            return;
        }
        int mid=l+r>>1;
        build(u<<1,l,mid,w),build(u<<1|1,mid+1,r,w);
        pushup(u);
    }
    void modify(int u,int pos,int val)
    {
    
    
        if(tree[u].l==tree[u].r)
        {
    
    
            tree[u].val=val;
            return;
        }
        int mid=tree[u].l+tree[u].r>>1;
        if(pos<=mid) modify(u<<1,pos,val);
        else modify(u<<1|1,pos,val);
        pushup(u);
    }
    int query(int u,int l,int r)
    {
    
    
        if(tree[u].l>=l&&tree[u].r<=r) return tree[u].val;
        
        int v=0;
        int mid=tree[u].l+tree[u].r>>1;
        if(l<=mid) v^=query(u<<1,l,r);
        if(r>mid) v^=query(u<<1|1,l,r);
        return v;
    }
    int cquery(int u,int v)
    {
    
    
        int val=0;
        while(top[u]!=top[v])
        {
    
    
            if(dep[top[u]]<dep[top[v]]) swap(u,v);
            val^=query(1,dfn[top[u]],dfn[u]);
            u=fa[top[u]];
        }
        if(dep[u]>dep[v]) swap(u,v);
        val^=query(1,dfn[u],dfn[v]);
        return val;
    }
}A,B;
int main()
{
    
    
    //IO;
    int T=1;
    //cin>>T;
    while(T--)
    {
    
    
        n=read(),q=read();
        memset(h,-1,sizeof h);
        for(int i=1;i<=n;i++) w[i]=read();
        for(int i=1;i<n;i++)
        {
    
    
            int u,v;
            u=read(),v=read();
            add(u,v),add(v,u);
        }
        dfs1(1,0);
        dfs2(1,1);
        for(int i=1;i<=n;i++)
        {
    
    
            if(dep[i]&1) a[dfn[i]]=w[i];
            else b[dfn[i]]=w[i];
        }
        A.build(1,1,n,a);
        B.build(1,1,n,b);
        while(q--)
        {
    
    
            int op,x,y;
            op=read(),x=read(),y=read();
            if(op==1)
            {
    
    
                if(dep[x]&1) A.modify(1,dfn[x],y);
                else B.modify(1,dfn[x],y);
            }
            else
            {
    
    
                int d=dist(x,y);
                int res=0;
                if(d&1)
                {
    
    
                    res=A.cquery(x,y)^B.cquery(x,y);
                }
                else
                {
    
    
                    if(dep[x]&1) res=B.cquery(x,y);
                    else res=A.cquery(x,y);
                }
                cout<<res<<'\n';
            }
            
        }
    }
    return 0;
    
}

要加油哦~

猜你喜欢

转载自blog.csdn.net/Fighting_Peter/article/details/108901628