想法1:用stl中的set优化哈希表。
哈希表是我们最经常用的一种快速存储和查找元素的方式,一般大家都会取一个大质数来当对一个数取模,然后存在链表里面,由于取模的数字很大,所以我们期望(有可能啦,反正不一定)这个算法插入和查询都是O(1)的,看起来是很优秀的复杂度,具体代码见下方。
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<map>
#define MOD 10000007
using namespace std;
int h[MOD],ne=0 ;
struct data {
int w,key, next ;
}Hash_table[1000004];
void insert(int x){
int t=x%MOD;
Hash_table[++ne].w=x;
Hash_table[ne].next=h[t];
h[t]=ne;
}
bool find(int x){
int t=x%MOD;
for(int i=h[t];i;i=Hash_table[i].next){
if(Hash_table[i].w==x)return true;
}
return false;
}
int n,x,m;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&x);
insert(x);
}
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%d",&x);
if(find(x))puts("Yes");
else puts("No");
}
return 0;
}
不过话说回来如果有一种情况,如果你的取模的数字取的不够优秀,那么可能会出现一个表头接的元素非常多,那么要是一个表头接了特别多的元素,O(1)的理想时间复杂度就会被破坏。那么,我们应该怎么避免这种问题呢?——我想出了一种机智的方法,将每一个个链表换成一个个stl_map,看起来最低的复杂度可以控制在O(logn)范围内。下面看代码实现。
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<map>
#define MOD 10000007
using namespace std;
std::map<int,bool>Hash_table[MOD];
void add(int x){
int t=x%MOD;
Hash_table[t][x]=1;
}
bool find(int x){
int t=x%MOD;
return Hash_table[t].count(x) ;
}
int n,x,m;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&x);
add(x);
}
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%d",&x);
if(find(x))puts("Yes");
else puts("No");
}
return 0;
}
**想法2:用stack代替queue来执行spfa **
在判断负权环的时候,我们一般使用spfa算法,不过由于元素多次入队,会导致时间复杂度激增。对于这个问题我想到一种方法,如果使用栈代替队列来跑spfa,由于负权环是不断更新的,那么我们的栈就可以每次找出最新更新的一个点,这样可以大大减少元素入队的次数。优化掉一定的常数。
下面是两种判环的测试结果
(下面那个是stack,上面的是queue)
还是有一点小优化的好吧。。。
下面是实现:
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<map>
#include<stack>
#include<queue>
#define MOD 10000007
using namespace std;
stack<int>q;
int n,m,w;
struct edge{
int to,next,w;
}e[250004];
int ne=1,h[1004],F,dis[1004],cnt[1004];
bool inq[1004];
void insert(int u,int v,int w){
e[++ne].to=v;
e[ne].next=h[u];
e[ne].w=w;
h[u]=ne;
}
void RESET(){
memset(inq,0,sizeof(inq));
memset(h,0,sizeof(h));
memset(cnt,0,sizeof(cnt));
ne=1;
}
bool spfa(int ask){
q.push(ask);
memset(dis,127/3,sizeof(dis));
dis[ask]=0;inq[ask]=1;
while(!q.empty()){
int x=q.top();q.pop();
cnt[x]++;
if(cnt[x]>=n)return 1;
for(int i=h[x];i;i=e[i].next){
if(dis[e[i].to]>dis[x]+e[i].w){
dis[e[i].to]=dis[x]+e[i].w;
if(!inq[e[i].to]){
inq[e[i].to]=1;
q.push(e[i].to);
}
}
}
inq[x]=0;
}
return 0;
}
void WORK(){
RESET();
scanf("%d%d%d",&n,&m,&w);
for(int i=1;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
insert(u,v,w);insert(v,u,w);
}
for(int i=1;i<=w;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
insert(u,v,-w);
}
if(spfa(1))puts("YES");
else puts("NO");
}
int main(){
scanf("%d",&F);
while(F--)WORK();
return 0;
}
想法3:人工栈线段树
我也不知道是怎么想出来的,而且看实际评测情况其实比普通线段树还要慢一点。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<stack>
using namespace std;
struct data{
int l , r ;long long tag , w ;
} tr[650004];
struct E{int a,b,k;long long w;};
E make_E(int k,int a,int b,long long w){
E GG;GG.k=k;GG.a=a;GG.b=b;GG.w=w;return GG;
}
int n,Q,up=1;
long long a[200004];
stack<E>st;
void build(int k,int l,int r){
tr[k].l=l;tr[k].r=r;
if(l==r){
tr[k].w=a[l];return;
}
int mid=l+r>>1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
tr[k].w=tr[k<<1].w+tr[k<<1|1].w;
}
void pushdown(int k){
long long q = tr[k].tag;
tr[k].tag = 0;
tr[k<<1].tag += q; tr[k<<1|1].tag += q;
tr[k<<1].w += (tr[k<<1].r - tr[k<<1].l + 1LL) * q;
tr[k<<1|1].w += (tr[k<<1|1].r - tr[k<<1|1].l + 1LL) * q;
}
void add(int a,int b,long long w){
int l,r,mid,k;
st.push(make_E(1,a,b,w));
while(!st.empty()){
E x = st.top();st.pop();
k=x.k;l=tr[k].l;r=tr[k].r;
tr[k].w += (x.b-x.a+1LL)*x.w;
if(l==x.a&&r==x.b){
tr[k].tag += w;
continue;
}
pushdown(k);
mid=l+r>>1;
if(x.b<=mid)st.push(make_E(k<<1,x.a,x.b,x.w));
else if(x.a>mid)st.push(make_E(k<<1|1,x.a,x.b,x.w));
else {
st.push(make_E(k<<1,x.a,mid,x.w));
st.push(make_E(k<<1|1,mid+1,x.b,x.w));
}
}
}
long long query(int a,int b){
long long ans=0;int l,r,mid,k;
st.push(make_E(1,a,b,0));
while(!st.empty()){
E x = st.top(); st.pop();
k=x.k;
l=tr[k].l,r=tr[k].r;
if(l==x.a&&r==x.b){ans+=tr[k].w;continue;}
pushdown(k);
mid=l+r>>1;
if(x.b<=mid)st.push(make_E(k<<1,x.a,x.b,0));
else if(x.a>mid)st.push(make_E(k<<1|1,x.a,x.b,0));
else{
st.push(make_E(k<<1,x.a,mid,0));
st.push(make_E(k<<1|1,mid+1,x.b,0));
}
}
return ans;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
build(1,1,n);
scanf("%d",&Q);
while(Q--){
int t,a,b;long long w;
scanf("%d",&t);
if(t == 1){
scanf("%d%d%lld",&a,&b,&w);
add(a,b,w);
}
if(t == 2){
scanf("%d%d",&a,&b);
printf("%lld\n",query(a,b));
}
}
return 0;
}