集合求交,51nod1818,根号分治

news/2024/11/16 6:43:00/

正题

      Portal

      这题发现总的元素数量不超过M,所以我们可以对一个集合内的元素数量来根号分治。

      当询问的|S_p|<T时,暴力维护每一个权值以位置为关键字的线段树(动态开点),这部分的时间复杂度是O(m \log_2 n+mT\log_2 n )

      当询问的|S_p|>=T时,我们对于这些特殊的集合维护一个以位置为关键字的树状数组,每个位置的权值就是该集合与特殊集合的交集,更新显然,每次查询直接差分前缀和即可。这部分的时间复杂度为O(\frac{m}{T}m\log_2n+m\log_2n)

      这两个都是最坏时间复杂度,当T=\sqrt m时,有最小时间复杂度。

      但是为了避免麻烦,我们可以直接设为T=\left \lceil \frac{m}{1000} \right \rceil。就保证了特殊集合最多只有1000个。

      发现空间上还是爆炸,直接考虑把空间开小一点,或者选择vector,因为实际上的特殊集合并没有那么多。

      反正我空间是卡过去的,时间上没有问题。

#include<cmath>
#include<cstdio>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iostream>
#define lowbit(x) (x&(-x))
using namespace std;const int N=40010,M=200010,A=1000000;
int n,m,bound,tot,num;
vector<int> S[N],V[A+1];
bool tf[501][A+1];
int root[A+1],id[N];
int t[M*16],ls[M*16],rs[M*16];
int sum[501][N];void insert(int&now,int d,int l,int r){if(now==0) now=++num;t[now]++;if(l==r) return ;int mid=(l+r)/2;if(d<=mid) insert(ls[now],d,l,mid);else insert(rs[now],d,mid+1,r);
}void add(int*now,int x,int t){while(x<=n){now[x]+=t;x+=lowbit(x);}return ;
}int get_tot(int now,int x,int y,int l,int r){if(x==l && y==r) return t[now];int mid=(l+r)/2;if(y<=mid) return get_tot(ls[now],x,y,l,mid);else if(mid<x) return get_tot(rs[now],x,y,mid+1,r);else return get_tot(ls[now],x,mid,l,mid)+get_tot(rs[now],mid+1,y,mid+1,r);
}int get_sum(int*now,int x){long long tot=0;while(x){tot+=now[x];x-=lowbit(x);}return tot;
}int main(){char c[2];int x,y,l;scanf("%d %d",&n,&m);bound=ceil(m/1000.0);while(m--){scanf("%s %d %d",c,&x,&y);if(c[0]=='I'){S[x].push_back(y);if(S[x].size()==bound){id[x]=++tot;for(int j=0;j<S[x].size();j++) tf[id[x]][S[x][j]]=true;for(int j=1;j<=n;j++) {int t=0;for(int k=0;k<S[j].size();k++) if(tf[id[x]][S[j][k]]) t+=S[j][k];if(t){add(sum[id[x]],j,t);if(j!=x && id[j] && tf[id[j]][y]) add(sum[id[j]],x,y);}}}else if(S[x].size()>bound){tf[id[x]][y]=true;for(int j=0;j<V[y].size();j++){add(sum[id[x]],V[y][j],y);if(id[V[y][j]]) add(sum[id[V[y][j]]],x,y);}add(sum[id[x]],x,y);}else if(S[x].size()<bound) for(int j=1;j<=tot;j++) if(tf[j][y]) add(sum[j],x,y);insert(root[y],x,1,n);V[y].push_back(x);}else{scanf("%d",&l);if(S[x].size()<bound){int tot=0;for(int j=0;j<S[x].size();j++)tot+=get_tot(root[S[x][j]],y,l,1,n)*S[x][j];printf("%d\n",tot);}else if(S[x].size()>=bound) printf("%d\n",get_sum(sum[id[x]],l)-get_sum(sum[id[x]],y-1));}}
}

 


http://www.ppmy.cn/news/244207.html

相关文章

HDU 1818 RP problem解题报告

一开始&#xff0c;我想的是建一个矩阵&#xff0c;然后尽量多的乘&#xff0c;做快速幂&#xff0c;做到后面会自然稳定&#xff0c;但是没去实现&#xff0c;考虑到一个问题&#xff0c;每个点的出度不一样&#xff0c;所以不是简单的求和&#xff0c;而且后面改边又要做矩阵…

BZOJ 1818: [Cqoi2010]内部白点

Description 如果一个点左右上下都有黑点&#xff0c;那么这个点也会变成黑点&#xff0c;问最后有多少个黑点\(n\leqslant 10^5\). Solution 扫描线. 显然变化后的点并不会产生新点&#xff0c;因为他的产生就需要他上下左右有点。 可以把他们转化成一些横纵的互不相交的直线.…

eoj1818 dijkstra求最短路及其条数

求出有n(1 < n < 100)个结点有向图中&#xff0c;结点1到结点n的最短路径&#xff0c;以及最短路径的条数。 Input 第一行有2个整数n和m( 0 < m < 3000)&#xff0c;接下来m行每行有三个整数u,v,w结点u到v之间有一条权为w的边(w<100000)。 Output 输出只有一…

自考总结:202304考期

考虑成绩昨天刚出&#xff0c;打算做下2023年4月考期的总结。 报考 202304考期报了三科&#xff1a;数据结构导论、管理经济学、信息系统开发与管理。这三科之中&#xff0c;除了信息系统开发与管理已经考过 2 次了&#xff0c;数据结构导论上次学了弃考了&#xff08;考前复…

bzoj 1818/1732 聚会

首先&#xff0c;答案的点一定在三组lca中的一个上 它在那个最深的lca上&#xff0c;不要问我为什么 或者&#xff0c;这三组lca一定有两个重复的&#xff0c;答案是那个不重复的。 #include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>…

Yolov5 (v6.1)添加注意力机制

Apply Transformer in the backbone 1、要把注意力结构代码放到common.py文件中 2、手把手带你Yolov5 (v6.1)添加注意力机制(一)&#xff08;并附上30多种顶会Attention原理图&#xff09; 3、手把手带你Yolov5 (v6.1)添加注意力机制(二)&#xff08;在C3模块中加入注意力机…

最新万能门店小程序V5.1.0 独立版源码

使用说明&#xff08;更详细配置见程序根目录下的pdf文档&#xff09;&#xff1a; 1&#xff0c;宝塔新建网站&#xff0c;网站运行目录要指向/public 2&#xff0c;开启SSL&#xff0c;配置好伪静态 3&#xff0c;把网址www.niumawu.com批量替换为你自己的网址 4&#xff0c…

NOI 1818:红与黑(C++)

题目地址&#xff1a;http://noi.openjudge.cn/ch0205/1818/ 题目&#xff1a;求地图中能到达的黑砖总数 一开始没有思路&#xff0c;参考了&#xff1a;http://blog.csdn.net/c20190102/article/details/52329390 思路&#xff1a;简单搜索 使用二维数组保存地图&#xff…