CodeForces 960F Pathwalks (主席树结构+动态开点思想+DP)

题目链接:http://codeforces.com/problemset/problem/960/F

题目大意

给定m个三元组(x,y,z),
要求找出符合条件的最大长度序列,
其序列要求是:相邻两个,
xi=yj&&zi>zj&&j<i.

题目分析

对于这种转移条件的要求,
很明显就是个Dp,然后考虑用啥数据结构维护下就行了,
之前遇到的多的是用树状数组或是线段树维护,
大体套路就是对于当前位置,收集可以利用到的最大计数,
去更新未来可能被影响到的状态位。
那么分析这道题,如果我们对于每个位置都开一个树维护一个区间,
表示以i长度结尾的dp值是多少,那么对于当前位置三元组我们可以
通过x定位到那个树直接区间查询,然后把答案更新到y树上。
最重要的一点是其空间如果全开的话会爆炸,
利用到主席树的思想,对于单点更新,我们只增加一条链,
所以主席树构架一套就好了,当然我感觉还有动态开点的思想在里面。

#include<bits/stdc++.h>
using namespace std;

#define debug puts("YES");
#define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
#define ll long long

#define lrt int l,int r,int rt
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define root l,r,rt
#define mst(a,b) memset((a),(b),sizeof(a))
#define pii pair<int,int>
#define fi first
#define se second
#define mk(x,y) make_pair(x,y)
const int mod=1e9+7;
const int maxn=1e5+5;
const int ub=1e6;
ll powmod(ll x,ll y){ll t; for(t=1;y;y>>=1,x=x*x%mod) if(y&1) t=t*x%mod; return t;}
ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
/*
题目大意:
给定m个三元组(x,y,z),
要求找出符合条件的最大长度序列,
其序列要求是:相邻两个,
xi=yj&&zi>zj&&j<i.

题目分析:
对于这种转移条件的要求,
很明显就是个Dp,然后考虑用啥数据结构维护下就行了,
之前遇到的多的是用树状数组或是线段树维护,
大体套路就是对于当前位置,收集可以利用到的最大计数,
去更新未来可能被影响到的状态位。
那么分析这道题,如果我们对于每个位置都开一个树维护一个区间,
表示以i长度结尾的dp值是多少,那么对于当前位置三元组我们可以
通过x定位到那个树直接区间查询,然后把答案更新到y树上。
最重要的一点是其空间如果全开的话会爆炸,
利用到主席树的思想,对于单点更新,我们只增加一条链,
所以主席树构架一套就好了,当然我感觉还有动态开点的思想在里面。
*/
int n,m,ans=0,tot=0;
int rt[maxn],ls[maxn*20],rs[maxn*20],sum[maxn*20];
void update(int& o,int last,int l,int r,int p,int v){
    o=++tot;
    ls[o]=ls[last],rs[o]=rs[last];
    if(l==r){
        sum[o]=max(sum[o],v);
        return ;
    }
    int mid=l+r>>1;
    if(p<=mid) update(ls[o],ls[o],l,mid,p,v);
    else update(rs[o],rs[o],mid+1,r,p,v);
    sum[o]=max(sum[ls[o]],sum[rs[o]]);
}
int query(int o,int l,int r,int L,int R){
    if(L>R) return 0;
    if(L<=l&&r<=R) return sum[o];
    int mid=l+r>>1,ans=0;
    if(L<=mid) ans=max(ans,query(ls[o],l,mid,L,R));
    if(mid<R) ans=max(ans,query(rs[o],mid+1,r,L,R));
    return ans;
}
int main(){
    cin>>n>>m;
    rep(i,1,m+1){
        int x,y,z;
        cin>>x>>y>>z;
        int ret=query(rt[x],0,maxn,0,z-1);
        update(rt[y],rt[y],0,maxn,z,ret+1);
        ans=max(ans,ret+1);
    }
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37451344/article/details/88748620
今日推荐