BZOJ3443: 装备合成

41 篇文章 0 订阅

可以发现,装备的合成是一个树形结构
对于一次合成,新建一个点表示这两个装备合成后的装备,成为这两个装备的父亲(一定要新建因为要兹瓷询问某个装备被合成前的属性)
然后某个装备的某个属性就相当于问这个装备的子树中某个属性的最大值,线段树在dfs序上查找就行了,因为属性数不多,对每种属性开一棵线段树

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1e9
using namespace std;

inline void read(int &x)
{
    char c;
    while(!((c=getchar())>='0'&&c<='9'));
    x=c-'0';
    while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
inline int _max(const int &x,const int &y){return x>y?x:y;}

const int maxn = 3100;
const int maxm = 450;
const int maxq = 210000;

int n,m,q;
int s[maxn][maxm];

struct edge
{
    int y,nex;
    edge(){}
    edge(const int &_y,const int &_nex){y=_y;nex=_nex;}
}a[maxn<<1]; int len,fir[maxn];
inline void ins(const int x,const int y){a[++len]=edge(y,fir[x]);fir[x]=len;}

int siz[maxn],fa[maxn],id[maxn],dfn,N;
int idx[maxn];
void dfs(const int x)
{
    siz[x]=1; id[x]=++dfn; idx[dfn]=x;
    for(int k=fir[x];k;k=a[k].nex)
    {
        const int y=a[k].y;
        if(y!=fa[x])
        {
            fa[y]=x;
            dfs(y);
            siz[x]+=siz[y];
        }
    }
}

int seg[maxm][maxn<<2],loc,c,k,lx,rx;
void build_(const int x,const int l,const int r)
{
    if(l==r) { seg[k][x]=s[idx[l]][k]; return ; }
    int mid=l+r>>1,lc=x<<1,rc=lc|1;
    build_(lc,l,mid); build_(rc,mid+1,r);
    seg[k][x]=_max(seg[k][lc],seg[k][rc]);
}
void upd(const int x,const int l,const int r)
{
    if(l==r) { seg[k][x]=c; return ; }
    int mid=l+r>>1,lc=x<<1,rc=lc|1;
    if(loc<=mid) upd(lc,l,mid);
    else upd(rc,mid+1,r);
    seg[k][x]=_max(seg[k][lc],seg[k][rc]);
}
int query(const int x,const int l,const int r)
{
    if(r<lx||rx<l) return 0;
    if(lx<=l&&r<=rx) return seg[k][x];
    int mid=l+r>>1,lc=x<<1,rc=lc|1;
    return _max(query(lc,l,mid),query(rc,mid+1,r));
}

int nowi[maxn];
bool live[maxn];
struct qu
{
    int k,a,b,c;
}b[maxq];

int main()
{
    read(n); read(m); read(q); N=n;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) read(s[i][j]);

    for(int i=1;i<=n;i++) nowi[i]=i,live[i]=true;
    for(int i=1;i<=q;i++)
    {
        int x,y;
        read(b[i].k); read(x); read(y); read(b[i].c);
        b[i].a=x; b[i].b=y;
        if(b[i].k==1)
        {
            ins(++N,nowi[x]); ins(nowi[x],N);
            ins(N,nowi[y]); ins(nowi[y],N);
            nowi[y]=N;
            live[x]=false;
        }
    }
    N++;
    for(int i=1;i<=n;i++) if(live[i]) ins(N,nowi[i]);

    dfn=0; dfs(N);
    for(int i=1;i<=m;i++) k=i,build_(1,1,dfn);
    for(int i=1;i<=n;i++) nowi[i]=i;

    for(int i=1;i<=q;i++)
    {
        int x=nowi[b[i].a],y=b[i].b;
        if(b[i].k==1) nowi[y]=fa[nowi[y]];
        if(b[i].k==2) k=y,lx=id[x],rx=lx+siz[x]-1,printf("%d\n",query(1,1,dfn));
        if(b[i].k==3) k=b[i].b,loc=id[b[i].a],c=b[i].c,upd(1,1,dfn);
    }

    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值