• Normal Data Structure Tricks


    放一些比较常见的数据结构处理技巧,会一点一点补上来。

    P3313 [SDOI2014]旅行

    给你一个 \(10^5\) 长的序列,每个点有颜色 \(c\) 和权值 \(v\)

    有修改和查询操作,修改可以为修改一个点的颜色或权值,查询一段区间内颜色为 \(c\) 的点的点权最大值以及权值和。

    $\texttt{solution}$

    发现直接对于每个颜色开一个动态开点线段树就做完了。

    每次操作最多只会建立 \(\log n\) 个节点,所以复杂度也是对滴。

    原题只不过讲上面的操作放在了树上,我直接莽一个树剖上去就做完了。

    嘴巴完跑路。

    P2056 [ZJOI2007]捉迷藏

    单点修改,维护全局最大、次大值。

    \(n\le 2\times 10^5\)

    $\texttt{solution}$

    一种常数超级大的想法是用 muiltiset,但是不建议尝试。

    我们可以维护两个队,分别维护存在的与不存在的值。

    如果加入一个值,就向第一个堆中添加元素;如果删除一个值,就向第二个堆中添加元素。

    查询的时候如果两个堆中的元素相同,就同时 pop,最后可以留下需要的值。

    原题就是这个技巧反复运用再套上氡态淀粉质啦!

    彩虹路径

    一棵树上每条边可以选择一些颜色,每条边可以选择的颜色给定,定义一条路径的美观度为:路径上相邻两条边且颜色不同的边的对数。查询从 \(u\)\(v\) 路径上的美观度最大为多少。

    \(n\le 10^5\)

    $\texttt{solution}$

    \(\bigstar\):发现如果一条边的颜色数量大于 \(3\),那么一定存在对于所有询问的一组最优解,这条边仅仅使用了三种颜色。

    那么可以随机选择三种颜色作为这条边的备选颜色,之后倍增 dp 乱跑即可。

    $\texttt{code}$
    #define Maxn 100005
    #define Maxm 300005
    #define Maxpown 22
    int n,m,q,tot;
    int hea[Maxn],nex[Maxm<<1],ver[Maxm<<1],edg[Maxm<<1];
    int hav[Maxn],col[Maxn][3],fa[Maxpown][Maxn],dep[Maxn];
    struct DP
    {
    	 int dp[3][3],ucol[3],vcol[3];
    	 inline void init()
    	 {
    	 	 ucol[0]=ucol[1]=ucol[2]=0;
    	 	 vcol[0]=vcol[1]=vcol[2]=0;
    	 	 for(int i=0;i<3;i++) for(int j=0;j<3;j++)
    		  	 dp[i][j]=-inf;
    	 }
    	 inline int query()
    	 {
    	 	 int maxx=-inf;
    	 	 for(int i=0;i<3;i++) for(int j=0;j<3;j++)
    	 	 	 maxx=max(maxx,dp[i][j]);
    	 	 return maxx;
    	 }
    };
    DP a[Maxpown][Maxn];
    inline DP merge(DP x,DP y)
    { // xl - xr - yl - yr 相接 
    	 if(!x.ucol[0]) return y;
    	 if(!y.ucol[0]) return x;
    	 DP ret; ret.init();
    	 for(int lx=0;lx<3;lx++) ret.ucol[lx]=x.ucol[lx];
    	 for(int ry=0;ry<3;ry++) ret.vcol[ry]=y.vcol[ry];
    	 for(int lx=0;lx<3;lx++) for(int ry=0;ry<3;ry++)
    	 {
    	 	 if(!x.ucol[lx] || !y.vcol[ry]) continue;
    	 	 for(int rx=0;rx<3;rx++) for(int ly=0;ly<3;ly++)
    	 	 {
    	 	 	 if(!x.vcol[rx] || !y.ucol[ly]) continue;
    	 	 	 ret.dp[lx][ry]=max(ret.dp[lx][ry],
    			   	 x.dp[lx][rx]+y.dp[ly][ry]+
    					 ((x.vcol[rx]!=y.ucol[ly])?1:0));
    		 }
    	 }
    	 return ret;
    }
    bool vis[Maxn];
    inline void add(int x,int y,int d)
    	 { ver[++tot]=y,nex[tot]=hea[x],hea[x]=tot,edg[tot]=d; }
    void Add(int x,int val)
    {
    	 if(hav[x]==3) return;
    	 bool p=false;
    	 for(int i=0;i<hav[x];i++) if(col[x][i]==val) p=true;
    	 if(!p) col[x][hav[x]++]=val;
    }
    void dfs(int x,int F)
    {
    	 vis[x]=true;
    	 for(int i=hea[x];i;i=nex[i])
    	 {
    	 	 if(ver[i]==F) continue;
    	 	 Add(ver[i],edg[i]);
    	 	 if(vis[ver[i]]) continue;
    	 	 fa[0][ver[i]]=x,dep[ver[i]]=dep[x]+1;
    	 	 for(int j=1;j<=20;j++)
    	 	 	 fa[j][ver[i]]=fa[j-1][fa[j-1][ver[i]]];
    	 	 dfs(ver[i],x);
    	 }
    }
    inline int query(int x,int y)
    {
    	 if(x==y) return 0;
    	 DP L,R; L.init(),R.init();
    	 if(dep[x]>dep[y]) swap(x,y);
    	 for(int i=20;i>=0;i--) if(dep[fa[i][y]]>=dep[x])
    	 	 R=merge(a[i][y],R),y=fa[i][y];
    	 if(x==y) return R.query();
    	 for(int i=20;i>=0;i--) if(fa[i][x]!=fa[i][y])
    	 	 L=merge(a[i][x],L),x=fa[i][x],
    	 	 R=merge(a[i][y],R),y=fa[i][y];
    	 L=merge(a[0][x],L),R=merge(a[0][y],R);
    	 int ret=-inf;
    	 for(int rx=0;rx<3;rx++) for(int ry=0;ry<3;ry++)
    	 {
    	 	 if(!L.vcol[rx] || !R.vcol[ry]) continue;
    	 	 for(int lx=0;lx<3;lx++) for(int ly=0;ly<3;ly++)
    	 	 {
    	 	 	 if(!L.ucol[lx] || !R.ucol[ly]) continue;
    	 	 	 ret=max(ret,L.dp[lx][rx]+R.dp[ly][ry]+
    			   	 ((L.ucol[lx]!=R.ucol[ly])?1:0));
    		 }
    	 }
    	 return ret;
    }
    int main()
    {
    	 n=rd(),m=rd();
    	 for(int i=1,x,y,d;i<=m;i++)
    	 	 x=rd(),y=rd(),d=rd(),add(x,y,d),add(y,x,d);
    	 dep[1]=1,dfs(1,0);
    	 for(int i=0;i<=20;i++) for(int j=0;j<=n;j++)
    	 	 a[i][j].init();
    	 for(int i=2;i<=n;i++) for(int j=0;j<hav[i];j++)
    	 {
    		 a[0][i].dp[j][j]=0,
    		 a[0][i].ucol[j]=a[0][i].vcol[j]=col[i][j];
    	 }
    	 for(int i=1;i<=20;i++)
    	 	 for(int j=2;j<=n;j++)
    	 	 	 a[i][j]=merge(a[i-1][fa[i-1][j]],a[i-1][j]);
    	 q=rd();
    	 for(int i=1,u,v;i<=q;i++)
    	 	 u=rd(),v=rd(),printf("%d\n",query(u,v));
    	 return 0;
    }
    
  • 相关阅读:
    初级算法梳理 -【任务1 线性回归算法梳理】
    【转】netstat 查看端口占用情况
    【转】Linux多命令顺序执行连接符(; || && |)
    【摘】程序员保持竞争力方法
    【整理】python中re的match、search、findall、finditer区别
    【转】怎样理解阻塞非阻塞与同步异步的区别?
    [笔记]Docker解决了什么问题?
    【笔记】第六章、Linux 的文件权限与目录配置
    [整理]Python程序员面试前需要看的博客(持续整理)
    【整理】知乎回答:为什么计算机语言中的变量名都不能够以数字为开头呢?
  • 原文地址:https://www.cnblogs.com/EricQian/p/15562764.html
Copyright © 2020-2023  润新知