dxy的脑洞。。(不定期更新,希望大佬们指出不足之处)

想法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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值