c题:
建立一棵树,对于每个跟节点表示一个pair
然后子节点是pair或者int
叶子节点必然为int
加判断一下就好了
D题:
可以想对于一个右边已经定下的点,只要前面有个数大于k个那么就可以统计这个所有之前的位置都是满足条件的
2 3 4 5 6 1 1 1.。。。。。假设k是3 那么在第三个1的位置可以匹配的个数就是2,3,4,5,6,1都可行。
首先离散化一下值,然后每次固定右边,找左边是否有大于k个的最右边位置,然后每次加上就好了
for(int i=1;i<=n;i++)
{
int v=a[i];
pos[v].pb(i);
int sz=pos[v].size();
//b[v]对应左边能往右到的元素在pos的位置
while(b[v]+k<sz)
{
b[v]++;
}
mx=max(mx,(long long)pos[v][b[v]]);
ans+=mx;
}
其中pos表示的是当前值最右边的位置
E题:
好题啊。
e题相当于反图的运用
首先裸的方法就是一个个用并差集来维护集合。
然后想优化。
对于一个已经在集合里面的点,那么在次搜到这个节点时相当于是无用的,因为已经在一个集合里面了。这条边就相当于废边。
然后如果我们用链表的形式写的话,就相当于每次要删除这样的无用边,裸着做的话铁定TLE 数据好大啊好大啊啊啊啊。。。。
然后这里有个巧妙的方法啊啊啊。
就是用并差集维护,维护后面要访问的点,如果在一个集合,那么就可以跳过去了,每次相当于跳到下一次没有在这个集合的点的位置。
就是说如果这个点有后面要访问的点,那么就相当于我们可以直接跳过这些已经访问的点(如果前向星的话就是head的数组直接往后跳),这样优化的话就可以了。。
开始写set建边+二分的查找超时了。。。虽然查找是logn但是每次logn还是受不了
可以用vector记录每次要找的下标下次再二分往后找 这样就好了
void dfs(int u)
{
ans[cnt].pb(u);
f[u]=u+1;
for(int j=0,i=find(1); i<=n; i=find(i+1))
{
j=lower_bound(mp[u].begin(),mp[u].end(),i)-mp[u].begin();
if(j>=mp[u].size() || mp[u][j]>i)
dfs(i);
}
}